Compare commits
211 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
798b56055d | ||
|
|
ce68e4a070 | ||
|
|
5da3130d26 | ||
|
|
6687cdc101 | ||
|
|
7e74ec6b62 | ||
|
|
b887fa70a5 | ||
|
|
1c6ab25253 | ||
|
|
1c43a3d1ee | ||
|
|
60ca1b3509 | ||
|
|
39d9312005 | ||
|
|
a0e42f5dfe | ||
|
|
7a3aff12a5 | ||
|
|
d4f1ef8704 | ||
|
|
a86d704bec | ||
|
|
57ab27aa5b | ||
|
|
909cc8b5d3 | ||
|
|
b7acbc4347 | ||
|
|
d276306ddc | ||
|
|
25b98b7ad2 | ||
|
|
819b424142 | ||
|
|
5d0328ba4b | ||
|
|
b219cff29c | ||
|
|
409eeaf962 | ||
|
|
4e5e8bd026 | ||
|
|
b91ec53ae0 | ||
|
|
ce0624b8b0 | ||
|
|
b4de2769cf | ||
|
|
3f7b0f1eb6 | ||
|
|
4055365c57 | ||
|
|
db7f782ca6 | ||
|
|
cde9d8d23a | ||
|
|
3dd9b0a2b6 | ||
|
|
59e54cecd2 | ||
|
|
5ed7e8efc2 | ||
|
|
fa85adfe0b | ||
|
|
a3e4f44a64 | ||
|
|
4a7a485e62 | ||
|
|
c353e02b3e | ||
|
|
1c2964cab4 | ||
|
|
47e083280a | ||
|
|
7db003100b | ||
|
|
f814b1ef47 | ||
|
|
f3d2ae366e | ||
|
|
b6ecce3aa2 | ||
|
|
c5235be9a7 | ||
|
|
23300de9d4 | ||
|
|
41dc57c84f | ||
|
|
85d1fe1ce6 | ||
|
|
ac6067ad53 | ||
|
|
173a62b5ce | ||
|
|
cbbafce73d | ||
|
|
2e74c19995 | ||
|
|
a212b7566c | ||
|
|
08faa52ef4 | ||
|
|
33bc4fffd9 | ||
|
|
eca2108e15 | ||
|
|
dab6034eb9 | ||
|
|
461e7d05d7 | ||
|
|
10c37b101d | ||
|
|
81f2c910f7 | ||
|
|
1fd97713c1 | ||
|
|
2d3eeed9ec | ||
|
|
b22eb6f12f | ||
|
|
dfb0a2a368 | ||
|
|
03bcc56429 | ||
|
|
457fda3fc3 | ||
|
|
54cee64610 | ||
|
|
477499248a | ||
|
|
3b70b6aeee | ||
|
|
163762e99e | ||
|
|
b99833df75 | ||
|
|
4be6231426 | ||
|
|
4673e3d511 | ||
|
|
00e48cc424 | ||
|
|
f8453825fb | ||
|
|
6cda9ab939 | ||
|
|
831d667896 | ||
|
|
17c342895a | ||
|
|
6ef518e6a0 | ||
|
|
ddee2fbb12 | ||
|
|
6512c2cdfb | ||
|
|
0eee05adaa | ||
|
|
17e0154ff3 | ||
|
|
2780f60c65 | ||
|
|
7dd3450362 | ||
|
|
ca4b2a61b8 | ||
|
|
d2ecd65ca5 | ||
|
|
03bd49f6c8 | ||
|
|
51607c5ed8 | ||
|
|
e2cbd3ee28 | ||
|
|
5944e6b57e | ||
|
|
efd46498ef | ||
|
|
3d705a737f | ||
|
|
996c57bccf | ||
|
|
a31e72ff06 | ||
|
|
f07d8fca8c | ||
|
|
69dbdee01f | ||
|
|
dedb9f3dc0 | ||
|
|
7d69b840fe | ||
|
|
4eaef300cb | ||
|
|
ec1a6b5edd | ||
|
|
adc5485c09 | ||
|
|
f622b2916d | ||
|
|
26be0cf948 | ||
|
|
e27c01fe5b | ||
|
|
d639e58fb9 | ||
|
|
0195c2cb48 | ||
|
|
068e2ec49b | ||
|
|
a9306b99ec | ||
|
|
3597194742 | ||
|
|
6f06ccec8e | ||
|
|
6fe7f220f9 | ||
|
|
45e70d493d | ||
|
|
ce71ab83f2 | ||
|
|
bf85d8facd | ||
|
|
c5ff7cdb2b | ||
|
|
f9ccf4f532 | ||
|
|
ab731f40a7 | ||
|
|
d8434fffa8 | ||
|
|
151b1d4510 | ||
|
|
168cf3e1f6 | ||
|
|
52dab0fa20 | ||
|
|
9257bab06e | ||
|
|
27f0a6f27a | ||
|
|
5bedbef2f2 | ||
|
|
51e7be8aa0 | ||
|
|
6c85bb39a3 | ||
|
|
07f7247707 | ||
|
|
f669711670 | ||
|
|
5f3671f349 | ||
|
|
1335cb699b | ||
|
|
84414b87c0 | ||
|
|
a1ecd4a501 | ||
|
|
d7e6f2ee41 | ||
|
|
04870fb8b3 | ||
|
|
9d196b78f7 | ||
|
|
4229525928 | ||
|
|
d861fecdb8 | ||
|
|
f280e23095 | ||
|
|
ed0e1d92c0 | ||
|
|
d82fc22659 | ||
|
|
6616d6788c | ||
|
|
322a7cf033 | ||
|
|
0f487c10ba | ||
|
|
11417144bd | ||
|
|
dafc59b163 | ||
|
|
566f9a80c4 | ||
|
|
89a42c5648 | ||
|
|
83ffbb00e8 | ||
|
|
84913cecab | ||
|
|
998bb09a92 | ||
|
|
cd68a8db54 | ||
|
|
df8477d180 | ||
|
|
244fbae0ce | ||
|
|
19e08a52c0 | ||
|
|
6389b1bb73 | ||
|
|
cadcbf6106 | ||
|
|
118f007ca6 | ||
|
|
cbb32bd29d | ||
|
|
9858dcd740 | ||
|
|
1fb76d135b | ||
|
|
bb62c8b2f1 | ||
|
|
2cbe7bf885 | ||
|
|
6043f6b74d | ||
|
|
ef1366592a | ||
|
|
01cf9fb8f3 | ||
|
|
285c406d5d | ||
|
|
ad29e52a57 | ||
|
|
3cfe207c83 | ||
|
|
c7e65cbc40 | ||
|
|
b8e02efb04 | ||
|
|
c7f20fb836 | ||
|
|
28a0202ef4 | ||
|
|
164e947045 | ||
|
|
7e65c0c87d | ||
|
|
9c1f753f17 | ||
|
|
0f821eb52d | ||
|
|
e3aadd63ab | ||
|
|
aa06d520df | ||
|
|
4fa1d4ba97 | ||
|
|
ba9f11b345 | ||
|
|
4777dd2e5e | ||
|
|
64b4591b72 | ||
|
|
bac5961fd8 | ||
|
|
b3cac862d8 | ||
|
|
b8ab2ad539 | ||
|
|
618d5bd5e9 | ||
|
|
096c3278b3 | ||
|
|
c9d9976c22 | ||
|
|
65497f93d4 | ||
|
|
af8a53bef6 | ||
|
|
916b856e97 | ||
|
|
7848da63f2 | ||
|
|
f359a1d31a | ||
|
|
72d645feae | ||
|
|
72fe382bba | ||
|
|
d25e840cf5 | ||
|
|
df1775572a | ||
|
|
86670cd49f | ||
|
|
31a4bf906e | ||
|
|
599291e8b7 | ||
|
|
f5a04fb9fb | ||
|
|
88558b67c3 | ||
|
|
d52cb255e0 | ||
|
|
6c214cbc37 | ||
|
|
01012c1448 | ||
|
|
4c7befb910 | ||
|
|
b62669ec8f | ||
|
|
0fb74caf9b | ||
|
|
9623dac01f | ||
|
|
695b27968c |
22
.travis.yml
Normal file
22
.travis.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
language: java
|
||||||
|
|
||||||
|
jdk:
|
||||||
|
- oraclejdk8
|
||||||
|
|
||||||
|
services:
|
||||||
|
- mongodb
|
||||||
|
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
- PROFILE=ci
|
||||||
|
- PROFILE=mongo-next
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.m2
|
||||||
|
|
||||||
|
install: true
|
||||||
|
|
||||||
|
script: "mvn clean dependency:list test -P${PROFILE} -Dsort"
|
||||||
@@ -11,7 +11,7 @@ For a comprehensive treatment of all the Spring Data MongoDB features, please re
|
|||||||
* the [User Guide](http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/)
|
* the [User Guide](http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/)
|
||||||
* the [JavaDocs](http://docs.spring.io/spring-data/mongodb/docs/current/api/) have extensive comments in them as well.
|
* the [JavaDocs](http://docs.spring.io/spring-data/mongodb/docs/current/api/) have extensive comments in them as well.
|
||||||
* the home page of [Spring Data MongoDB](http://projects.spring.io/spring-data-mongodb) contains links to articles and other resources.
|
* the home page of [Spring Data MongoDB](http://projects.spring.io/spring-data-mongodb) contains links to articles and other resources.
|
||||||
* for more detailed questions, use the [forum](http://forum.spring.io/forum/spring-projects/data/nosql).
|
* for more detailed questions, use [Spring Data Mongodb on Stackoverflow](http://stackoverflow.com/questions/tagged/spring-data-mongodb).
|
||||||
|
|
||||||
If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://projects.spring.io/).
|
If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://projects.spring.io/).
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ 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>1.4.1.RELEASE</version>
|
<version>1.5.0.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>1.5.0.BUILD-SNAPSHOT</version>
|
<version>1.6.0.BUILD-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
@@ -139,7 +139,7 @@ public class MyService {
|
|||||||
|
|
||||||
Here are some ways for you to get involved in the community:
|
Here are some ways for you to get involved in the community:
|
||||||
|
|
||||||
* Get involved with the Spring community on the Spring Community Forums. Please help out on the [forum](http://forum.spring.io/forum/spring-projects/data/nosql) by responding to questions and joining the debate.
|
* Get involved with the Spring community on Stackoverflow and help out on the [spring-data-mongodb](http://stackoverflow.com/questions/tagged/spring-data-mongodb) tag by responding to questions and joining the debate.
|
||||||
* Create [JIRA](https://jira.springframework.org/browse/DATADOC) tickets for bugs and new features and comment and vote on the ones that you are interested in.
|
* Create [JIRA](https://jira.springframework.org/browse/DATADOC) tickets for bugs and new features and comment and vote on the ones that you are interested in.
|
||||||
* Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](http://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing.
|
* Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](http://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing.
|
||||||
* Watch for upcoming articles on Spring by [subscribing](http://spring.io/blog) to spring.io.
|
* Watch for upcoming articles on Spring by [subscribing](http://spring.io/blog) to spring.io.
|
||||||
|
|||||||
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>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<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>1.4.0.M1</version>
|
<version>1.6.0.RC1</version>
|
||||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.type>multi</project.type>
|
<project.type>multi</project.type>
|
||||||
<dist.id>spring-data-mongodb</dist.id>
|
<dist.id>spring-data-mongodb</dist.id>
|
||||||
<springdata.commons>1.8.0.M1</springdata.commons>
|
<springdata.commons>1.10.0.RC1</springdata.commons>
|
||||||
<mongo>2.11.4</mongo>
|
<mongo>2.13.0</mongo>
|
||||||
<mongo-osgi>${mongo}</mongo-osgi>
|
<mongo.osgi>2.13.0</mongo.osgi>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
@@ -105,11 +105,44 @@
|
|||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile>
|
<profile>
|
||||||
|
|
||||||
<id>mongo-next</id>
|
<id>mongo-next</id>
|
||||||
<properties>
|
<properties>
|
||||||
<mongo>2.12.0-rc0</mongo>
|
<mongo>2.13.0-SNAPSHOT</mongo>
|
||||||
<mongo-osgi>2.12.0</mongo-osgi>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>mongo-snapshots</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
|
||||||
|
<id>mongo3</id>
|
||||||
|
<properties>
|
||||||
|
<mongo>3.0.0-beta3</mongo>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
|
||||||
|
<id>mongo3-next</id>
|
||||||
|
<properties>
|
||||||
|
<mongo>3.0.0-SNAPSHOT</mongo>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>mongo-snapshots</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
@@ -125,7 +158,7 @@
|
|||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-libs-milestone</id>
|
<id>spring-libs-milestone</id>
|
||||||
<url>http://repo.spring.io/libs-milestone/</url>
|
<url>http://repo.spring.io/libs-milestone</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
|||||||
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>
|
||||||
@@ -6,7 +6,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>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<name>Spring Data MongoDB - Cross-Store Support</name>
|
<name>Spring Data MongoDB - Cross-Store Support</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<jpa>1.0.0.Final</jpa>
|
<jpa>2.0.0</jpa>
|
||||||
<hibernate>3.6.10.Final</hibernate>
|
<hibernate>3.6.10.Final</hibernate>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -56,17 +56,13 @@
|
|||||||
<artifactId>aspectjrt</artifactId>
|
<artifactId>aspectjrt</artifactId>
|
||||||
<version>${aspectj}</version>
|
<version>${aspectj}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>cglib</groupId>
|
|
||||||
<artifactId>cglib</artifactId>
|
|
||||||
<version>2.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- JPA -->
|
<!-- JPA -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
<artifactId>javax.persistence</artifactId>
|
||||||
<version>${jpa}</version>
|
<version>${jpa}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- For Tests -->
|
<!-- For Tests -->
|
||||||
@@ -102,7 +98,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>aspectj-maven-plugin</artifactId>
|
<artifactId>aspectj-maven-plugin</artifactId>
|
||||||
<version>1.4</version>
|
<version>1.6</version>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.aspectj</groupId>
|
<groupId>org.aspectj</groupId>
|
||||||
@@ -131,8 +127,10 @@
|
|||||||
<artifactId>spring-aspects</artifactId>
|
<artifactId>spring-aspects</artifactId>
|
||||||
</aspectLibrary>
|
</aspectLibrary>
|
||||||
</aspectLibraries>
|
</aspectLibraries>
|
||||||
|
<complianceLevel>${source.level}</complianceLevel>
|
||||||
<source>${source.level}</source>
|
<source>${source.level}</source>
|
||||||
<target>${source.level}</target>
|
<target>${source.level}</target>
|
||||||
|
<xmlConfigured>aop.xml</xmlConfigured>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Import-Package:
|
|||||||
Export-Template:
|
Export-Template:
|
||||||
org.springframework.data.mongodb.crossstore.*;version="${project.version}"
|
org.springframework.data.mongodb.crossstore.*;version="${project.version}"
|
||||||
Import-Template:
|
Import-Template:
|
||||||
com.mongodb.*;version="${mongo-osgi:[=.=.=,+1.0.0)}",
|
com.mongodb.*;version="${mongo.osgi:[=.=.=,+1.0.0)}",
|
||||||
javax.persistence.*;version="${jpa:[=.=.=,+1.0.0)}",
|
javax.persistence.*;version="${jpa:[=.=.=,+1.0.0)}",
|
||||||
org.aspectj.*;version="${aspectj:[1.0.0, 2.0.0)}",
|
org.aspectj.*;version="${aspectj:[1.0.0, 2.0.0)}",
|
||||||
org.bson.*;version="0",
|
org.bson.*;version="0",
|
||||||
|
|||||||
@@ -13,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>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -32,6 +32,10 @@
|
|||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>wagon-maven-plugin</artifactId>
|
<artifactId>wagon-maven-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.asciidoctor</groupId>
|
||||||
|
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,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>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ Bundle-ManifestVersion: 2
|
|||||||
Import-Package:
|
Import-Package:
|
||||||
sun.reflect;version="0";resolution:=optional
|
sun.reflect;version="0";resolution:=optional
|
||||||
Import-Template:
|
Import-Template:
|
||||||
com.mongodb.*;version="${mongo-osgi:[=.=.=,+1.0.0)}",
|
com.mongodb.*;version="${mongo.osgi:[=.=.=,+1.0.0)}",
|
||||||
org.apache.log4j.*;version="${log4j:[=.=.=,+1.0.0)}"
|
org.apache.log4j.*;version="${log4j:[=.=.=,+1.0.0)}"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<context version="7.1.9.205">
|
<context version="7.1.10.209">
|
||||||
<scope type="Project" name="spring-data-mongodb">
|
<scope type="Project" name="spring-data-mongodb">
|
||||||
<element type="TypeFilterReferenceOverridden" name="Filter">
|
<element type="TypeFilterReferenceOverridden" name="Filter">
|
||||||
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.**"/>
|
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.**"/>
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
<element type="IncludeTypePattern" name="**.config.**"/>
|
<element type="IncludeTypePattern" name="**.config.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API" type="AllowedDependency"/>
|
||||||
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation" type="AllowedDependency"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency toName="Project|spring-data-mongodb::Layer|Config" type="AllowedDependency"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Config" type="AllowedDependency"/>
|
||||||
|
|||||||
@@ -11,13 +11,14 @@
|
|||||||
<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>1.5.0.M1</version>
|
<version>1.7.0.RC1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<validation>1.0.0.GA</validation>
|
<validation>1.0.0.GA</validation>
|
||||||
<objenesis>1.3</objenesis>
|
<objenesis>1.3</objenesis>
|
||||||
|
<equalsverifier>1.5</equalsverifier>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -137,6 +138,13 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.threeten</groupId>
|
||||||
|
<artifactId>threetenbp</artifactId>
|
||||||
|
<version>${threetenbp}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>jul-to-slf4j</artifactId>
|
<artifactId>jul-to-slf4j</artifactId>
|
||||||
@@ -144,6 +152,12 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>nl.jqno.equalsverifier</groupId>
|
||||||
|
<artifactId>equalsverifier</artifactId>
|
||||||
|
<version>${equalsverifier}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -189,9 +203,14 @@
|
|||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<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>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
|
<properties>
|
||||||
|
<property>
|
||||||
|
<name>listener</name>
|
||||||
|
<value>org.springframework.data.mongodb.test.util.CleanMongoDBJunitRunListener</value>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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.
|
||||||
@@ -28,6 +28,9 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
|
|||||||
import org.springframework.data.annotation.Persistent;
|
import org.springframework.data.annotation.Persistent;
|
||||||
import org.springframework.data.authentication.UserCredentials;
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||||
|
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||||
|
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||||
|
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||||
@@ -35,7 +38,6 @@ import org.springframework.data.mongodb.core.convert.CustomConversions;
|
|||||||
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.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
|
||||||
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.CachingIsNewStrategyFactory;
|
||||||
@@ -44,6 +46,7 @@ import org.springframework.util.ClassUtils;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Spring Data MongoDB configuration using JavaConfig.
|
* Base class for Spring Data MongoDB configuration using JavaConfig.
|
||||||
@@ -51,6 +54,8 @@ import com.mongodb.Mongo;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Ryan Tenney
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public abstract class AbstractMongoConfiguration {
|
public abstract class AbstractMongoConfiguration {
|
||||||
@@ -67,7 +72,10 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
* returned by {@link #getDatabaseName()} later on effectively.
|
* returned by {@link #getDatabaseName()} later on effectively.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||||
|
* {@link MongoClient#getCredentialsList()}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected String getAuthenticationDatabaseName() {
|
protected String getAuthenticationDatabaseName() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -126,7 +134,10 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
* be used.
|
* be used.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||||
|
* {@link MongoClient#getCredentialsList()}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected UserCredentials getUserCredentials() {
|
protected UserCredentials getUserCredentials() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -144,10 +155,7 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
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());
|
||||||
if (abbreviateFieldNames()) {
|
|
||||||
mappingContext.setFieldNamingStrategy(new CamelCaseAbbreviatingFieldNamingStrategy());
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappingContext;
|
return mappingContext;
|
||||||
}
|
}
|
||||||
@@ -232,4 +240,15 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
protected boolean abbreviateFieldNames() {
|
protected boolean abbreviateFieldNames() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a {@link FieldNamingStrategy} on the {@link MongoMappingContext} instance created.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
protected FieldNamingStrategy fieldNamingStrategy() {
|
||||||
|
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
|
||||||
|
: PropertyNameFieldNamingStrategy.INSTANCE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
|||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
|
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||||
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;
|
||||||
@@ -51,10 +52,10 @@ 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.context.MappingContextIsNewStrategyFactory;
|
||||||
|
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
||||||
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
|
||||||
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.mongodb.core.mapping.event.ValidatingMongoEventListener;
|
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
|
||||||
@@ -71,6 +72,7 @@ import org.w3c.dom.Element;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Maciej Walkowiak
|
* @author Maciej Walkowiak
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
@@ -83,8 +85,11 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
*/
|
*/
|
||||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
if (parserContext.isNested()) {
|
||||||
|
parserContext.getReaderContext().error("Mongo Converter must not be defined as nested bean.", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||||
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;
|
||||||
|
|
||||||
@@ -209,11 +214,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
|
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
String abbreviateFieldNames = element.getAttribute("abbreviate-field-names");
|
parseFieldNamingStrategy(element, parserContext.getReaderContext(), mappingContextBuilder);
|
||||||
if ("true".equals(abbreviateFieldNames)) {
|
|
||||||
mappingContextBuilder.addPropertyValue("fieldNamingStrategy", new RootBeanDefinition(
|
|
||||||
CamelCaseAbbreviatingFieldNamingStrategy.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
: converterId + "." + MAPPING_CONTEXT_BEAN_NAME;
|
: converterId + "." + MAPPING_CONTEXT_BEAN_NAME;
|
||||||
@@ -222,6 +223,34 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
return ctxRef;
|
return ctxRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void parseFieldNamingStrategy(Element element, ReaderContext context, BeanDefinitionBuilder builder) {
|
||||||
|
|
||||||
|
String abbreviateFieldNames = element.getAttribute("abbreviate-field-names");
|
||||||
|
String fieldNamingStrategy = element.getAttribute("field-naming-strategy-ref");
|
||||||
|
|
||||||
|
boolean fieldNamingStrategyReferenced = StringUtils.hasText(fieldNamingStrategy);
|
||||||
|
boolean abbreviationActivated = StringUtils.hasText(abbreviateFieldNames)
|
||||||
|
&& Boolean.parseBoolean(abbreviateFieldNames);
|
||||||
|
|
||||||
|
if (fieldNamingStrategyReferenced && abbreviationActivated) {
|
||||||
|
context.error("Field name abbreviation cannot be activated if a field-naming-strategy-ref is configured!",
|
||||||
|
element);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
if ("true".equals(abbreviateFieldNames)) {
|
||||||
|
value = new RootBeanDefinition(CamelCaseAbbreviatingFieldNamingStrategy.class);
|
||||||
|
} else if (fieldNamingStrategyReferenced) {
|
||||||
|
value = new RuntimeBeanReference(fieldNamingStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
builder.addPropertyValue("fieldNamingStrategy", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
|
private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
|
List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
|
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||||
|
import org.springframework.data.config.ParsingUtils;
|
||||||
|
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for {@code mongo-client} definitions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
|
||||||
|
Object source = parserContext.extractSource(element);
|
||||||
|
String id = element.getAttribute("id");
|
||||||
|
|
||||||
|
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
|
||||||
|
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoClientFactoryBean.class);
|
||||||
|
|
||||||
|
ParsingUtils.setPropertyValue(builder, element, "port", "port");
|
||||||
|
ParsingUtils.setPropertyValue(builder, element, "host", "host");
|
||||||
|
ParsingUtils.setPropertyValue(builder, element, "credentials", "credentials");
|
||||||
|
|
||||||
|
MongoParsingUtils.parseMongoClientOptions(element, builder);
|
||||||
|
MongoParsingUtils.parseReplicaSet(element, builder);
|
||||||
|
|
||||||
|
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
||||||
|
|
||||||
|
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
|
||||||
|
|
||||||
|
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||||
|
parserContext.registerBeanComponent(mongoComponent);
|
||||||
|
|
||||||
|
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||||
|
.getServerAddressPropertyEditorBuilder());
|
||||||
|
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||||
|
|
||||||
|
BeanComponentDefinition writeConcernEditor = helper.getComponent(MongoParsingUtils
|
||||||
|
.getWriteConcernPropertyEditorBuilder());
|
||||||
|
parserContext.registerBeanComponent(writeConcernEditor);
|
||||||
|
|
||||||
|
BeanComponentDefinition readPreferenceEditor = helper.getComponent(MongoParsingUtils
|
||||||
|
.getReadPreferencePropertyEditorBuilder());
|
||||||
|
parserContext.registerBeanComponent(readPreferenceEditor);
|
||||||
|
|
||||||
|
BeanComponentDefinition credentialsEditor = helper.getComponent(MongoParsingUtils
|
||||||
|
.getMongoCredentialPropertyEditor());
|
||||||
|
parserContext.registerBeanComponent(credentialsEditor);
|
||||||
|
|
||||||
|
parserContext.popAndRegisterContainingComponent();
|
||||||
|
|
||||||
|
return mongoComponent.getBeanDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a {@link String} to a Collection of {@link MongoCredential}.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
|
||||||
|
private static final String USERNAME_PASSWORD_DELIMINATOR = ":";
|
||||||
|
private static final String DATABASE_DELIMINATOR = "@";
|
||||||
|
private static final String OPTIONS_DELIMINATOR = "?";
|
||||||
|
private static final String OPTION_VALUE_DELIMINATOR = "&";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setAsText(String text) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
|
||||||
|
|
||||||
|
for (String credentialString : text.split(",")) {
|
||||||
|
|
||||||
|
if (!text.contains(USERNAME_PASSWORD_DELIMINATOR) || !text.contains(DATABASE_DELIMINATOR)) {
|
||||||
|
throw new IllegalArgumentException("Credentials need to be in format 'username:password@database'!");
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] userNameAndPassword = extractUserNameAndPassword(credentialString);
|
||||||
|
String database = extractDB(credentialString);
|
||||||
|
Properties options = extractOptions(credentialString);
|
||||||
|
|
||||||
|
if (!options.isEmpty()) {
|
||||||
|
|
||||||
|
if (options.containsKey(AUTH_MECHANISM_KEY)) {
|
||||||
|
|
||||||
|
String authMechanism = options.getProperty(AUTH_MECHANISM_KEY);
|
||||||
|
|
||||||
|
if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {
|
||||||
|
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
|
||||||
|
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
|
||||||
|
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
|
||||||
|
userNameAndPassword[1].toCharArray()));
|
||||||
|
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
|
||||||
|
credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
|
||||||
|
} else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {
|
||||||
|
credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
|
||||||
|
userNameAndPassword[1].toCharArray()));
|
||||||
|
} else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {
|
||||||
|
credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
|
||||||
|
userNameAndPassword[1].toCharArray()));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Cannot create MongoCredentials for unknown auth mechanism '%s'!", authMechanism));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
credentials.add(MongoCredential.createCredential(userNameAndPassword[0], database,
|
||||||
|
userNameAndPassword[1].toCharArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] extractUserNameAndPassword(String text) {
|
||||||
|
|
||||||
|
int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
|
||||||
|
String userNameAndPassword = text.substring(0, dbSeperationIndex);
|
||||||
|
return userNameAndPassword.split(USERNAME_PASSWORD_DELIMINATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extractDB(String text) {
|
||||||
|
|
||||||
|
int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
|
||||||
|
|
||||||
|
String tmp = text.substring(dbSeperationIndex + 1);
|
||||||
|
int optionsSeperationIndex = tmp.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||||
|
|
||||||
|
return optionsSeperationIndex > -1 ? tmp.substring(0, optionsSeperationIndex) : tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Properties extractOptions(String text) {
|
||||||
|
|
||||||
|
int optionsSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||||
|
int dbSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||||
|
|
||||||
|
if (optionsSeperationIndex == -1 || dbSeperationIndex > optionsSeperationIndex) {
|
||||||
|
return new Properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
for (String option : text.substring(optionsSeperationIndex + 1).split(OPTION_VALUE_DELIMINATOR)) {
|
||||||
|
String[] optionArgs = option.split("=");
|
||||||
|
properties.put(optionArgs[0], optionArgs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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,6 +22,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Martin Baumgartner
|
* @author Martin Baumgartner
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
|||||||
|
|
||||||
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
||||||
registerBeanDefinitionParser("mongo", new MongoParser());
|
registerBeanDefinitionParser("mongo", new MongoParser());
|
||||||
|
registerBeanDefinitionParser("mongo-client", new MongoClientParser());
|
||||||
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
||||||
registerBeanDefinitionParser("jmx", new MongoJmxParser());
|
registerBeanDefinitionParser("jmx", new MongoJmxParser());
|
||||||
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());
|
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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,14 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.config;
|
package org.springframework.data.mongodb.config;
|
||||||
|
|
||||||
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.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.ManagedMap;
|
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
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;
|
||||||
@@ -36,6 +32,7 @@ import org.w3c.dom.Element;
|
|||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MongoParser implements BeanDefinitionParser {
|
public class MongoParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
@@ -64,7 +61,8 @@ public class MongoParser implements BeanDefinitionParser {
|
|||||||
|
|
||||||
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||||
parserContext.registerBeanComponent(mongoComponent);
|
parserContext.registerBeanComponent(mongoComponent);
|
||||||
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor());
|
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||||
|
.getServerAddressPropertyEditorBuilder());
|
||||||
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||||
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
|
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||||
.getWriteConcernPropertyEditorBuilder());
|
.getWriteConcernPropertyEditorBuilder());
|
||||||
@@ -75,19 +73,4 @@ public class MongoParser implements BeanDefinitionParser {
|
|||||||
return mongoComponent.getBeanDefinition();
|
return mongoComponent.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* container.
|
|
||||||
*/
|
|
||||||
private BeanDefinitionBuilder registerServerAddressPropertyEditor() {
|
|
||||||
|
|
||||||
Map<String, String> customEditors = new ManagedMap<String, String>();
|
|
||||||
customEditors.put("com.mongodb.ServerAddress[]",
|
|
||||||
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
|
||||||
builder.addPropertyValue("customEditors", customEditors);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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,6 +24,7 @@ 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.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.MongoClientOptionsFactoryBean;
|
||||||
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
|
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@@ -34,12 +35,12 @@ import org.w3c.dom.Element;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
abstract class MongoParsingUtils {
|
abstract class MongoParsingUtils {
|
||||||
|
|
||||||
private MongoParsingUtils() {
|
private MongoParsingUtils() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the mongo replica-set element.
|
* Parses the mongo replica-set element.
|
||||||
@@ -54,12 +55,14 @@ abstract class MongoParsingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
|
* Parses the {@code mongo:options} sub-element. Populates the given attribute factory with the proper attributes.
|
||||||
*
|
*
|
||||||
* @return true if parsing actually occured, false otherwise
|
* @return true if parsing actually occured, {@literal false} otherwise
|
||||||
*/
|
*/
|
||||||
static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
|
static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
|
||||||
|
|
||||||
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
|
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
|
||||||
|
|
||||||
if (optionsElement == null) {
|
if (optionsElement == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -87,6 +90,51 @@ abstract class MongoParsingUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the {@code mongo:client-options} sub-element. Populates the given attribute factory with the proper
|
||||||
|
* attributes.
|
||||||
|
*
|
||||||
|
* @param element must not be {@literal null}.
|
||||||
|
* @param mongoClientBuilder must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public static boolean parseMongoClientOptions(Element element, BeanDefinitionBuilder mongoClientBuilder) {
|
||||||
|
|
||||||
|
Element optionsElement = DomUtils.getChildElementByTagName(element, "client-options");
|
||||||
|
|
||||||
|
if (optionsElement == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(MongoClientOptionsFactoryBean.class);
|
||||||
|
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "description", "description");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-connections-per-host", "minConnectionsPerHost");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
|
||||||
|
"threadsAllowedToBlockForConnectionMultiplier");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
|
||||||
|
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");
|
||||||
|
|
||||||
|
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
||||||
* {@link WriteConcernPropertyEditor}.
|
* {@link WriteConcernPropertyEditor}.
|
||||||
@@ -103,4 +151,56 @@ abstract class MongoParsingUtils {
|
|||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* container.
|
||||||
|
*/
|
||||||
|
static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
|
||||||
|
|
||||||
|
Map<String, String> customEditors = new ManagedMap<String, String>();
|
||||||
|
customEditors.put("com.mongodb.ServerAddress[]",
|
||||||
|
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
||||||
|
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||||
|
builder.addPropertyValue("customEditors", customEditors);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
||||||
|
* {@link ReadPreferencePropertyEditor}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
|
||||||
|
|
||||||
|
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
|
||||||
|
customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.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 MongoCredentialPropertyEditor}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static BeanDefinitionBuilder getMongoCredentialPropertyEditor() {
|
||||||
|
|
||||||
|
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
|
||||||
|
customEditors.put("com.mongodb.MongoCredential[]", MongoCredentialPropertyEditor.class);
|
||||||
|
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||||
|
builder.addPropertyValue("customEditors", customEditors);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 com.mongodb.ReadPreference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a {@link String} to a {@link ReadPreference}.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setAsText(String readPreferenceString) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
if (readPreferenceString == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadPreference preference = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
preference = ReadPreference.valueOf(readPreferenceString);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// ignore this one and try to map it differently
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preference != null) {
|
||||||
|
setValue(preference);
|
||||||
|
} else if ("PRIMARY".equalsIgnoreCase(readPreferenceString)) {
|
||||||
|
setValue(ReadPreference.primary());
|
||||||
|
} else if ("PRIMARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
|
||||||
|
setValue(ReadPreference.primaryPreferred());
|
||||||
|
} else if ("SECONDARY".equalsIgnoreCase(readPreferenceString)) {
|
||||||
|
setValue(ReadPreference.secondary());
|
||||||
|
} else if ("SECONDARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
|
||||||
|
setValue(ReadPreference.secondaryPreferred());
|
||||||
|
} else if ("NEAREST".equalsIgnoreCase(readPreferenceString)) {
|
||||||
|
setValue(ReadPreference.nearest());
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot find matching ReadPreference for %s",
|
||||||
|
readPreferenceString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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,6 +18,8 @@ package org.springframework.data.mongodb.core;
|
|||||||
import static org.springframework.data.domain.Sort.Direction.*;
|
import static org.springframework.data.domain.Sort.Direction.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
@@ -36,11 +38,13 @@ import com.mongodb.MongoException;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Komi Innocent
|
* @author Komi Innocent
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class DefaultIndexOperations implements IndexOperations {
|
public class DefaultIndexOperations implements IndexOperations {
|
||||||
|
|
||||||
private static final Double ONE = Double.valueOf(1);
|
private static final Double ONE = Double.valueOf(1);
|
||||||
private static final Double MINUS_ONE = Double.valueOf(-1);
|
private static final Double MINUS_ONE = Double.valueOf(-1);
|
||||||
|
private static final Collection<String> TWO_D_IDENTIFIERS = Arrays.asList("2d", "2dsphere");
|
||||||
|
|
||||||
private final MongoOperations mongoOperations;
|
private final MongoOperations mongoOperations;
|
||||||
private final String collectionName;
|
private final String collectionName;
|
||||||
@@ -69,9 +73,9 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
DBObject indexOptions = indexDefinition.getIndexOptions();
|
DBObject indexOptions = indexDefinition.getIndexOptions();
|
||||||
if (indexOptions != null) {
|
if (indexOptions != null) {
|
||||||
collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
|
collection.createIndex(indexDefinition.getIndexKeys(), indexOptions);
|
||||||
} else {
|
} else {
|
||||||
collection.ensureIndex(indexDefinition.getIndexKeys());
|
collection.createIndex(indexDefinition.getIndexKeys());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -104,10 +108,12 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
|
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void resetIndexCache() {
|
public void resetIndexCache() {
|
||||||
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
|
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
|
||||||
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
collection.resetIndexCache();
|
|
||||||
|
ReflectiveDBCollectionInvoker.resetIndexCache(collection);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -140,8 +146,15 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
|
|
||||||
Object value = keyDbObject.get(key);
|
Object value = keyDbObject.get(key);
|
||||||
|
|
||||||
if ("2d".equals(value)) {
|
if (TWO_D_IDENTIFIERS.contains(value)) {
|
||||||
indexFields.add(IndexField.geo(key));
|
indexFields.add(IndexField.geo(key));
|
||||||
|
} else if ("text".equals(value)) {
|
||||||
|
|
||||||
|
DBObject weights = (DBObject) ix.get("weights");
|
||||||
|
for (String fieldName : weights.keySet()) {
|
||||||
|
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Double keyValue = new Double(value.toString());
|
Double keyValue = new Double(value.toString());
|
||||||
@@ -159,8 +172,8 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
boolean unique = ix.containsField("unique") ? (Boolean) ix.get("unique") : false;
|
boolean unique = ix.containsField("unique") ? (Boolean) ix.get("unique") : false;
|
||||||
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean) ix.get("dropDups") : false;
|
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean) ix.get("dropDups") : false;
|
||||||
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
|
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
|
||||||
|
String language = ix.containsField("default_language") ? (String) ix.get("default_language") : "";
|
||||||
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse));
|
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language));
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexInfoList;
|
return indexInfoList;
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2015 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
|
||||||
|
*
|
||||||
|
* http://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 static java.util.UUID.*;
|
||||||
|
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||||
|
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||||
|
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.MongoException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
class DefaultScriptOperations implements ScriptOperations {
|
||||||
|
|
||||||
|
private static final String SCRIPT_COLLECTION_NAME = "system.js";
|
||||||
|
private static final String SCRIPT_NAME_PREFIX = "func_";
|
||||||
|
|
||||||
|
private final MongoOperations mongoOperations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new {@link DefaultScriptOperations} using given {@link MongoOperations}.
|
||||||
|
*
|
||||||
|
* @param mongoOperations must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public DefaultScriptOperations(MongoOperations mongoOperations) {
|
||||||
|
|
||||||
|
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||||
|
|
||||||
|
this.mongoOperations = mongoOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.ExecutableMongoScript)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public NamedMongoScript register(ExecutableMongoScript script) {
|
||||||
|
return register(new NamedMongoScript(generateScriptName(), script));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.NamedMongoScript)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public NamedMongoScript register(NamedMongoScript script) {
|
||||||
|
|
||||||
|
Assert.notNull(script, "Script must not be null!");
|
||||||
|
|
||||||
|
mongoOperations.save(script, SCRIPT_COLLECTION_NAME);
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.ExecutableMongoScript, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object execute(final ExecutableMongoScript script, final Object... args) {
|
||||||
|
|
||||||
|
Assert.notNull(script, "Script must not be null!");
|
||||||
|
|
||||||
|
return mongoOperations.execute(new DbCallback<Object>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||||
|
return db.eval(script.getCode(), convertScriptArgs(args));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#call(java.lang.String, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object call(final String scriptName, final Object... args) {
|
||||||
|
|
||||||
|
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||||
|
|
||||||
|
return mongoOperations.execute(new DbCallback<Object>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||||
|
return db.eval(String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean exists(String scriptName) {
|
||||||
|
|
||||||
|
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||||
|
|
||||||
|
return mongoOperations.exists(query(where("name").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.ScriptOperations#getScriptNames()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<String> getScriptNames() {
|
||||||
|
|
||||||
|
List<NamedMongoScript> scripts = mongoOperations.findAll(NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(scripts)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> scriptNames = new HashSet<String>();
|
||||||
|
|
||||||
|
for (NamedMongoScript script : scripts) {
|
||||||
|
scriptNames.add(script.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return scriptNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] convertScriptArgs(Object... args) {
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(args)) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> convertedValues = new ArrayList<Object>(args.length);
|
||||||
|
|
||||||
|
for (Object arg : args) {
|
||||||
|
convertedValues.add(arg instanceof String ? String.format("'%s'", arg) : this.mongoOperations.getConverter()
|
||||||
|
.convertToMongoType(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertedValues.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertAndJoinScriptArgs(Object... args) {
|
||||||
|
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a valid name for the {@literal JavaScript}. MongoDB requires an id of type String for scripts. Calling
|
||||||
|
* scripts having {@link ObjectId} as id fails. Therefore we create a random UUID without {@code -} (as this won't
|
||||||
|
* work) an prefix the result with {@link #SCRIPT_NAME_PREFIX}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String generateScriptName() {
|
||||||
|
return SCRIPT_NAME_PREFIX + randomUUID().toString().replaceAll("-", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-2015 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,12 +20,12 @@ import java.util.List;
|
|||||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index operations on a collection.
|
* Index operations on a collection.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public interface IndexOperations {
|
public interface IndexOperations {
|
||||||
|
|
||||||
@@ -51,7 +51,11 @@ public interface IndexOperations {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all indices that have not yet been applied to this collection.
|
* Clears all indices that have not yet been applied to this collection.
|
||||||
|
*
|
||||||
|
* @deprecated since 1.7. The MongoDB Java driver version 3.0 does no longer support reseting the index cache.
|
||||||
|
* @throws {@link UnsupportedOperationException} when used with MongoDB Java driver version 3.0.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void resetIndexCache();
|
void resetIndexCache();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoClientOptions;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenient factory for configuring MongoDB.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||||
|
|
||||||
|
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||||
|
|
||||||
|
private MongoClientOptions mongoClientOptions;
|
||||||
|
private String host;
|
||||||
|
private Integer port;
|
||||||
|
private List<ServerAddress> replicaSetSeeds;
|
||||||
|
private List<MongoCredential> credentials;
|
||||||
|
|
||||||
|
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link MongoClientOptions} to be used when creating {@link MongoClient}.
|
||||||
|
*
|
||||||
|
* @param mongoClientOptions
|
||||||
|
*/
|
||||||
|
public void setMongoClientOptions(MongoClientOptions mongoClientOptions) {
|
||||||
|
this.mongoClientOptions = mongoClientOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of credentials to be used when creating {@link MongoClient}.
|
||||||
|
*
|
||||||
|
* @param credentials can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public void setCredentials(MongoCredential[] credentials) {
|
||||||
|
this.credentials = filterNonNullElementsAsList(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of {@link ServerAddress} to build up a replica set for.
|
||||||
|
*
|
||||||
|
* @param replicaSetSeeds can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
|
||||||
|
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the host to connect to.
|
||||||
|
*
|
||||||
|
* @param host
|
||||||
|
*/
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the port to connect to.
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
*/
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link PersistenceExceptionTranslator} to use.
|
||||||
|
*
|
||||||
|
* @param exceptionTranslator
|
||||||
|
*/
|
||||||
|
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||||
|
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||||
|
*/
|
||||||
|
public Class<? extends Mongo> getObjectType() {
|
||||||
|
return Mongo.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||||
|
*/
|
||||||
|
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||||
|
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Mongo createInstance() throws Exception {
|
||||||
|
|
||||||
|
if (mongoClientOptions == null) {
|
||||||
|
mongoClientOptions = MongoClientOptions.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials == null) {
|
||||||
|
credentials = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createMongoClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void destroyInstance(Mongo instance) throws Exception {
|
||||||
|
instance.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MongoClient createMongoClient() throws UnknownHostException {
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(replicaSetSeeds)) {
|
||||||
|
return new MongoClient(replicaSetSeeds, credentials, mongoClientOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MongoClient(createConfiguredOrDefaultServerAddress(), credentials, mongoClientOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerAddress createConfiguredOrDefaultServerAddress() throws UnknownHostException {
|
||||||
|
|
||||||
|
ServerAddress defaultAddress = new ServerAddress();
|
||||||
|
|
||||||
|
return new ServerAddress(StringUtils.hasText(host) ? host : defaultAddress.getHost(),
|
||||||
|
port != null ? port.intValue() : defaultAddress.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given array as {@link List} with all {@literal null} elements removed.
|
||||||
|
*
|
||||||
|
* @param elements the elements to filter <T>, can be {@literal null}.
|
||||||
|
* @return a new unmodifiable {@link List#} from the given elements without {@literal null}s.
|
||||||
|
*/
|
||||||
|
private static <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||||
|
|
||||||
|
if (elements == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> candidateElements = new ArrayList<T>();
|
||||||
|
|
||||||
|
for (T element : elements) {
|
||||||
|
if (element != null) {
|
||||||
|
candidateElements.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(candidateElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 javax.net.SocketFactory;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||||
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
|
||||||
|
import com.mongodb.DBDecoderFactory;
|
||||||
|
import com.mongodb.DBEncoderFactory;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoClientOptions;
|
||||||
|
import com.mongodb.ReadPreference;
|
||||||
|
import com.mongodb.WriteConcern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory bean for construction of a {@link MongoClientOptions} instance.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClientOptions> {
|
||||||
|
|
||||||
|
private static final MongoClientOptions DEFAULT_MONGO_OPTIONS = MongoClientOptions.builder().build();
|
||||||
|
|
||||||
|
private String description = DEFAULT_MONGO_OPTIONS.getDescription();
|
||||||
|
private int minConnectionsPerHost = DEFAULT_MONGO_OPTIONS.getMinConnectionsPerHost();
|
||||||
|
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
|
||||||
|
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
|
||||||
|
.getThreadsAllowedToBlockForConnectionMultiplier();
|
||||||
|
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
|
||||||
|
private int maxConnectionIdleTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionIdleTime();
|
||||||
|
private int maxConnectionLifeTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionLifeTime();
|
||||||
|
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
|
||||||
|
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
|
||||||
|
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
|
||||||
|
private ReadPreference readPreference = DEFAULT_MONGO_OPTIONS.getReadPreference();
|
||||||
|
private DBDecoderFactory dbDecoderFactory = DEFAULT_MONGO_OPTIONS.getDbDecoderFactory();
|
||||||
|
private DBEncoderFactory dbEncoderFactory = DEFAULT_MONGO_OPTIONS.getDbEncoderFactory();
|
||||||
|
private WriteConcern writeConcern = DEFAULT_MONGO_OPTIONS.getWriteConcern();
|
||||||
|
private SocketFactory socketFactory = DEFAULT_MONGO_OPTIONS.getSocketFactory();
|
||||||
|
private boolean cursorFinalizerEnabled = DEFAULT_MONGO_OPTIONS.isCursorFinalizerEnabled();
|
||||||
|
private boolean alwaysUseMBeans = DEFAULT_MONGO_OPTIONS.isAlwaysUseMBeans();
|
||||||
|
private int heartbeatFrequency = DEFAULT_MONGO_OPTIONS.getHeartbeatFrequency();
|
||||||
|
private int minHeartbeatFrequency = DEFAULT_MONGO_OPTIONS.getMinHeartbeatFrequency();
|
||||||
|
private int heartbeatConnectTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatConnectTimeout();
|
||||||
|
private int heartbeatSocketTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatSocketTimeout();
|
||||||
|
private String requiredReplicaSetName = DEFAULT_MONGO_OPTIONS.getRequiredReplicaSetName();
|
||||||
|
|
||||||
|
private boolean ssl;
|
||||||
|
private SSLSocketFactory sslSocketFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link MongoClient} description.
|
||||||
|
*
|
||||||
|
* @param description
|
||||||
|
*/
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the minimum number of connections per host.
|
||||||
|
*
|
||||||
|
* @param minConnectionsPerHost
|
||||||
|
*/
|
||||||
|
public void setMinConnectionsPerHost(int minConnectionsPerHost) {
|
||||||
|
this.minConnectionsPerHost = minConnectionsPerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of connections allowed per host. Will block if run out. Default is 10. System property
|
||||||
|
* {@code MONGO.POOLSIZE} can override
|
||||||
|
*
|
||||||
|
* @param connectionsPerHost
|
||||||
|
*/
|
||||||
|
public void setConnectionsPerHost(int connectionsPerHost) {
|
||||||
|
this.connectionsPerHost = connectionsPerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the multiplier for connectionsPerHost for # of threads that can block. Default is 5. If connectionsPerHost is
|
||||||
|
* 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an
|
||||||
|
* exception will be thrown.
|
||||||
|
*
|
||||||
|
* @param threadsAllowedToBlockForConnectionMultiplier
|
||||||
|
*/
|
||||||
|
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
||||||
|
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the max wait time of a blocking thread for a connection. Default is 12000 ms (2 minutes)
|
||||||
|
*
|
||||||
|
* @param maxWaitTime
|
||||||
|
*/
|
||||||
|
public void setMaxWaitTime(int maxWaitTime) {
|
||||||
|
this.maxWaitTime = maxWaitTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum idle time for a pooled connection.
|
||||||
|
*
|
||||||
|
* @param maxConnectionIdleTime
|
||||||
|
*/
|
||||||
|
public void setMaxConnectionIdleTime(int maxConnectionIdleTime) {
|
||||||
|
this.maxConnectionIdleTime = maxConnectionIdleTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum life time for a pooled connection.
|
||||||
|
*
|
||||||
|
* @param maxConnectionLifeTime
|
||||||
|
*/
|
||||||
|
public void setMaxConnectionLifeTime(int maxConnectionLifeTime) {
|
||||||
|
this.maxConnectionLifeTime = maxConnectionLifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the connect timeout in milliseconds. 0 is default and infinite.
|
||||||
|
*
|
||||||
|
* @param connectTimeout
|
||||||
|
*/
|
||||||
|
public void setConnectTimeout(int connectTimeout) {
|
||||||
|
this.connectTimeout = connectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the socket timeout. 0 is default and infinite.
|
||||||
|
*
|
||||||
|
* @param socketTimeout
|
||||||
|
*/
|
||||||
|
public void setSocketTimeout(int socketTimeout) {
|
||||||
|
this.socketTimeout = socketTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the keep alive flag, controls whether or not to have socket keep alive timeout. Defaults to false.
|
||||||
|
*
|
||||||
|
* @param socketKeepAlive
|
||||||
|
*/
|
||||||
|
public void setSocketKeepAlive(boolean socketKeepAlive) {
|
||||||
|
this.socketKeepAlive = socketKeepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link ReadPreference}.
|
||||||
|
*
|
||||||
|
* @param readPreference
|
||||||
|
*/
|
||||||
|
public void setReadPreference(ReadPreference readPreference) {
|
||||||
|
this.readPreference = readPreference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link WriteConcern} that will be the default value used when asking the {@link MongoDbFactory} for a DB
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @param writeConcern
|
||||||
|
*/
|
||||||
|
public void setWriteConcern(WriteConcern writeConcern) {
|
||||||
|
this.writeConcern = writeConcern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param socketFactory
|
||||||
|
*/
|
||||||
|
public void setSocketFactory(SocketFactory socketFactory) {
|
||||||
|
this.socketFactory = socketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the frequency that the driver will attempt to determine the current state of each server in the cluster.
|
||||||
|
*
|
||||||
|
* @param heartbeatFrequency
|
||||||
|
*/
|
||||||
|
public void setHeartbeatFrequency(int heartbeatFrequency) {
|
||||||
|
this.heartbeatFrequency = heartbeatFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the event that the driver has to frequently re-check a server's availability, it will wait at least this long
|
||||||
|
* since the previous check to avoid wasted effort.
|
||||||
|
*
|
||||||
|
* @param minHeartbeatFrequency
|
||||||
|
*/
|
||||||
|
public void setMinHeartbeatFrequency(int minHeartbeatFrequency) {
|
||||||
|
this.minHeartbeatFrequency = minHeartbeatFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the connect timeout for connections used for the cluster heartbeat.
|
||||||
|
*
|
||||||
|
* @param heartbeatConnectTimeout
|
||||||
|
*/
|
||||||
|
public void setHeartbeatConnectTimeout(int heartbeatConnectTimeout) {
|
||||||
|
this.heartbeatConnectTimeout = heartbeatConnectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the socket timeout for connections used for the cluster heartbeat.
|
||||||
|
*
|
||||||
|
* @param heartbeatSocketTimeout
|
||||||
|
*/
|
||||||
|
public void setHeartbeatSocketTimeout(int heartbeatSocketTimeout) {
|
||||||
|
this.heartbeatSocketTimeout = heartbeatSocketTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the name of the replica set.
|
||||||
|
*
|
||||||
|
* @param requiredReplicaSetName
|
||||||
|
*/
|
||||||
|
public void setRequiredReplicaSetName(String requiredReplicaSetName) {
|
||||||
|
this.requiredReplicaSetName = requiredReplicaSetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This controls if the driver should us an SSL connection. Defaults to |@literal false}.
|
||||||
|
*
|
||||||
|
* @param ssl
|
||||||
|
*/
|
||||||
|
public void setSsl(boolean ssl) {
|
||||||
|
this.ssl = ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link SSLSocketFactory} to use for the {@literal SSL} connection. If none is configured here,
|
||||||
|
* {@link SSLSocketFactory#getDefault()} will be used.
|
||||||
|
*
|
||||||
|
* @param sslSocketFactory
|
||||||
|
*/
|
||||||
|
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||||
|
this.sslSocketFactory = sslSocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected MongoClientOptions createInstance() throws Exception {
|
||||||
|
|
||||||
|
SocketFactory socketFactoryToUse = ssl ? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory
|
||||||
|
.getDefault()) : this.socketFactory;
|
||||||
|
|
||||||
|
return MongoClientOptions.builder() //
|
||||||
|
.alwaysUseMBeans(this.alwaysUseMBeans) //
|
||||||
|
.connectionsPerHost(this.connectionsPerHost) //
|
||||||
|
.connectTimeout(connectTimeout) //
|
||||||
|
.cursorFinalizerEnabled(cursorFinalizerEnabled) //
|
||||||
|
.dbDecoderFactory(dbDecoderFactory) //
|
||||||
|
.dbEncoderFactory(dbEncoderFactory) //
|
||||||
|
.description(description) //
|
||||||
|
.heartbeatConnectTimeout(heartbeatConnectTimeout) //
|
||||||
|
.heartbeatFrequency(heartbeatFrequency) //
|
||||||
|
.heartbeatSocketTimeout(heartbeatSocketTimeout) //
|
||||||
|
.maxConnectionIdleTime(maxConnectionIdleTime) //
|
||||||
|
.maxConnectionLifeTime(maxConnectionLifeTime) //
|
||||||
|
.maxWaitTime(maxWaitTime) //
|
||||||
|
.minConnectionsPerHost(minConnectionsPerHost) //
|
||||||
|
.minHeartbeatFrequency(minHeartbeatFrequency) //
|
||||||
|
.readPreference(readPreference) //
|
||||||
|
.requiredReplicaSetName(requiredReplicaSetName) //
|
||||||
|
.socketFactory(socketFactoryToUse) //
|
||||||
|
.socketKeepAlive(socketKeepAlive) //
|
||||||
|
.socketTimeout(socketTimeout) //
|
||||||
|
.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier) //
|
||||||
|
.writeConcern(writeConcern).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||||
|
*/
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return MongoClientOptions.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2015 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,12 +18,13 @@ package org.springframework.data.mongodb.core;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.authentication.UserCredentials;
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
||||||
@@ -34,6 +35,7 @@ import com.mongodb.Mongo;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Randy Watler
|
* @author Randy Watler
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public abstract class MongoDbUtils {
|
public abstract class MongoDbUtils {
|
||||||
@@ -43,9 +45,7 @@ public abstract class MongoDbUtils {
|
|||||||
/**
|
/**
|
||||||
* Private constructor to prevent instantiation.
|
* Private constructor to prevent instantiation.
|
||||||
*/
|
*/
|
||||||
private MongoDbUtils() {
|
private MongoDbUtils() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
|
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
|
||||||
@@ -65,11 +65,24 @@ public abstract class MongoDbUtils {
|
|||||||
* @param databaseName the database name, must not be {@literal null} or empty.
|
* @param databaseName the database name, must not be {@literal null} or empty.
|
||||||
* @param credentials the credentials to use, must not be {@literal null}.
|
* @param credentials the credentials to use, must not be {@literal null}.
|
||||||
* @return the {@link DB} connection
|
* @return the {@link DB} connection
|
||||||
|
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||||
|
* {@link MongoClient#getCredentialsList()}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
|
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||||
return getDB(mongo, databaseName, credentials, databaseName);
|
return getDB(mongo, databaseName, credentials, databaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mongo
|
||||||
|
* @param databaseName
|
||||||
|
* @param credentials
|
||||||
|
* @param authenticationDatabaseName
|
||||||
|
* @return
|
||||||
|
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||||
|
* {@link MongoClient#getCredentialsList()}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
|
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
String authenticationDatabaseName) {
|
String authenticationDatabaseName) {
|
||||||
|
|
||||||
@@ -109,22 +122,9 @@ public abstract class MongoDbUtils {
|
|||||||
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
|
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
|
||||||
|
|
||||||
DB db = mongo.getDB(databaseName);
|
DB db = mongo.getDB(databaseName);
|
||||||
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
|
|
||||||
|
|
||||||
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
if (requiresAuthDbAuthentication(credentials)) {
|
||||||
|
ReflectiveDbInvoker.authenticate(mongo, db, credentials, authenticationDatabaseName);
|
||||||
synchronized (authDb) {
|
|
||||||
|
|
||||||
if (credentialsGiven && !authDb.isAuthenticated()) {
|
|
||||||
|
|
||||||
String username = credentials.getUsername();
|
|
||||||
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
|
||||||
|
|
||||||
if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
|
|
||||||
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
|
||||||
+ credentials.toString(), databaseName, credentials);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TX sync active, bind new database to thread
|
// TX sync active, bind new database to thread
|
||||||
@@ -181,16 +181,36 @@ public abstract class MongoDbUtils {
|
|||||||
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
|
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
|
||||||
*
|
*
|
||||||
* @param db the DB to close (may be <code>null</code>)
|
* @param db the DB to close (may be <code>null</code>)
|
||||||
|
* @deprecated since 1.7. The main use case for this method is to ensure that applications can read their own
|
||||||
|
* unacknowledged writes, but this is no longer so prevalent since the MongoDB Java driver version 3
|
||||||
|
* started defaulting to acknowledged writes.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static void closeDB(DB db) {
|
public static void closeDB(DB db) {
|
||||||
|
|
||||||
if (db != null) {
|
if (db != null) {
|
||||||
LOGGER.debug("Closing Mongo DB object");
|
LOGGER.debug("Closing Mongo DB object");
|
||||||
try {
|
try {
|
||||||
db.requestDone();
|
ReflectiveDbInvoker.requestDone(db);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
|
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if credentials present. In case we're using a monog-java-driver version 3 or above we do not have the need
|
||||||
|
* for authentication as the auth data has to be provied within the MongoClient
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean requiresAuthDbAuthentication(UserCredentials credentials) {
|
||||||
|
|
||||||
|
if (credentials == null || !credentials.hasUsername()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !MongoClientVersion.isMongo3Driver();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2015 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,19 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
import org.springframework.dao.DataAccessResourceFailureException;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import com.mongodb.MongoException;
|
import com.mongodb.MongoException;
|
||||||
import com.mongodb.MongoException.CursorNotFound;
|
|
||||||
import com.mongodb.MongoException.DuplicateKey;
|
|
||||||
import com.mongodb.MongoException.Network;
|
|
||||||
import com.mongodb.MongoInternalException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
|
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
|
||||||
@@ -36,9 +38,23 @@ import com.mongodb.MongoInternalException;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Michal Vich
|
* @author Michal Vich
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
|
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
|
||||||
|
|
||||||
|
private static final Set<String> DULICATE_KEY_EXCEPTIONS = new HashSet<String>(Arrays.asList(
|
||||||
|
"MongoException.DuplicateKey", "DuplicateKeyException"));
|
||||||
|
|
||||||
|
private static final Set<String> RESOURCE_FAILURE_EXCEPTIONS = new HashSet<String>(Arrays.asList(
|
||||||
|
"MongoException.Network", "MongoSocketException", "MongoException.CursorNotFound",
|
||||||
|
"MongoCursorNotFoundException", "MongoServerSelectionException", "MongoTimeoutException"));
|
||||||
|
|
||||||
|
private static final Set<String> RESOURCE_USAGE_EXCEPTIONS = new HashSet<String>(
|
||||||
|
Arrays.asList("MongoInternalException"));
|
||||||
|
|
||||||
|
private static final Set<String> DATA_INTEGRETY_EXCEPTIONS = new HashSet<String>(
|
||||||
|
Arrays.asList("WriteConcernException"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||||
@@ -47,28 +63,25 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
|||||||
|
|
||||||
// Check for well-known MongoException subclasses.
|
// Check for well-known MongoException subclasses.
|
||||||
|
|
||||||
// All other MongoExceptions
|
String exception = ClassUtils.getShortName(ClassUtils.getUserClass(ex.getClass()));
|
||||||
if (ex instanceof DuplicateKey) {
|
|
||||||
|
if (DULICATE_KEY_EXCEPTIONS.contains(exception)) {
|
||||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ex instanceof Network) {
|
if (RESOURCE_FAILURE_EXCEPTIONS.contains(exception)) {
|
||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ex instanceof CursorNotFound) {
|
if (RESOURCE_USAGE_EXCEPTIONS.contains(exception)) {
|
||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Driver 2.12 throws this to indicate connection problems. String comparison to avoid hard dependency
|
|
||||||
if (ex.getClass().getName().equals("com.mongodb.MongoServerSelectionException")) {
|
|
||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex instanceof MongoInternalException) {
|
|
||||||
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
|
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DATA_INTEGRETY_EXCEPTIONS.contains(exception)) {
|
||||||
|
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other MongoExceptions
|
||||||
if (ex instanceof MongoException) {
|
if (ex instanceof MongoException) {
|
||||||
|
|
||||||
int code = ((MongoException) ex).getCode();
|
int code = ((MongoException) ex).getCode();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2015 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,9 +20,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||||
@@ -40,12 +38,14 @@ import com.mongodb.WriteConcern;
|
|||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
|
* @deprecated since 1.7. Please use {@link MongoClientFactoryBean} instead.
|
||||||
*/
|
*/
|
||||||
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, DisposableBean,
|
@Deprecated
|
||||||
PersistenceExceptionTranslator {
|
public class MongoFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||||
|
|
||||||
private Mongo mongo;
|
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||||
|
|
||||||
private MongoOptions mongoOptions;
|
private MongoOptions mongoOptions;
|
||||||
private String host;
|
private String host;
|
||||||
@@ -53,9 +53,11 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
private WriteConcern writeConcern;
|
private WriteConcern writeConcern;
|
||||||
private List<ServerAddress> replicaSetSeeds;
|
private List<ServerAddress> replicaSetSeeds;
|
||||||
private List<ServerAddress> replicaPair;
|
private List<ServerAddress> replicaPair;
|
||||||
|
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
|
||||||
|
|
||||||
private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
|
/**
|
||||||
|
* @param mongoOptions
|
||||||
|
*/
|
||||||
public void setMongoOptions(MongoOptions mongoOptions) {
|
public void setMongoOptions(MongoOptions mongoOptions) {
|
||||||
this.mongoOptions = mongoOptions;
|
this.mongoOptions = mongoOptions;
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,6 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
|
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
|
||||||
*
|
|
||||||
* @param replicaPair
|
* @param replicaPair
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@@ -75,30 +76,19 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param elements the elements to filter <T>
|
* Configures the host to connect to.
|
||||||
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
*
|
||||||
|
* @param host
|
||||||
*/
|
*/
|
||||||
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
|
||||||
|
|
||||||
if (elements == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<T> candidateElements = new ArrayList<T>();
|
|
||||||
|
|
||||||
for (T element : elements) {
|
|
||||||
if (element != null) {
|
|
||||||
candidateElements.add(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(candidateElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHost(String host) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the port to connect to.
|
||||||
|
*
|
||||||
|
* @param port
|
||||||
|
*/
|
||||||
public void setPort(int port) {
|
public void setPort(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
@@ -112,12 +102,13 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
this.writeConcern = writeConcern;
|
this.writeConcern = writeConcern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link PersistenceExceptionTranslator} to use.
|
||||||
|
*
|
||||||
|
* @param exceptionTranslator can be {@literal null}.
|
||||||
|
*/
|
||||||
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||||
this.exceptionTranslator = exceptionTranslator;
|
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
|
||||||
}
|
|
||||||
|
|
||||||
public Mongo getObject() throws Exception {
|
|
||||||
return mongo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -128,14 +119,6 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
return Mongo.class;
|
return Mongo.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
|
||||||
*/
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||||
@@ -146,10 +129,10 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
protected Mongo createInstance() throws Exception {
|
||||||
|
|
||||||
Mongo mongo;
|
Mongo mongo;
|
||||||
ServerAddress defaultOptions = new ServerAddress();
|
ServerAddress defaultOptions = new ServerAddress();
|
||||||
@@ -175,18 +158,42 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
mongo.setWriteConcern(writeConcern);
|
mongo.setWriteConcern(writeConcern);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mongo = mongo;
|
return mongo;
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isNullOrEmpty(Collection<?> elements) {
|
|
||||||
return elements == null || elements.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public void destroy() throws Exception {
|
@Override
|
||||||
this.mongo.close();
|
protected void destroyInstance(Mongo mongo) throws Exception {
|
||||||
|
mongo.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isNullOrEmpty(Collection<?> elements) {
|
||||||
|
return elements == null || elements.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given array as {@link List} with all {@literal null} elements removed.
|
||||||
|
*
|
||||||
|
* @param elements the elements to filter <T>
|
||||||
|
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
||||||
|
*/
|
||||||
|
private static <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||||
|
|
||||||
|
if (elements == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> candidateElements = new ArrayList<T>();
|
||||||
|
|
||||||
|
for (T element : elements) {
|
||||||
|
if (element != null) {
|
||||||
|
candidateElements.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(candidateElements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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,11 +19,11 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.GeoResults;
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
|
||||||
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
|
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
|
||||||
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
|
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
|
||||||
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
|
||||||
@@ -33,10 +33,14 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
|||||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update;
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
import org.springframework.data.util.CloseableIterator;
|
||||||
|
|
||||||
import com.mongodb.CommandResult;
|
import com.mongodb.CommandResult;
|
||||||
|
import com.mongodb.Cursor;
|
||||||
|
import com.mongodb.DB;
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
import com.mongodb.ReadPreference;
|
||||||
import com.mongodb.WriteResult;
|
import com.mongodb.WriteResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +56,6 @@ import com.mongodb.WriteResult;
|
|||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public interface MongoOperations {
|
public interface MongoOperations {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,9 +89,23 @@ public interface MongoOperations {
|
|||||||
*
|
*
|
||||||
* @param command a MongoDB command
|
* @param command a MongoDB command
|
||||||
* @param options query options to use
|
* @param options query options to use
|
||||||
|
* @deprecated since 1.7. Please use {@link #executeCommand(DBObject, ReadPreference)}, as the MongoDB Java driver
|
||||||
|
* version 3 no longer supports this operation.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
CommandResult executeCommand(DBObject command, int options);
|
CommandResult executeCommand(DBObject command, int options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's data
|
||||||
|
* access exception hierarchy.
|
||||||
|
*
|
||||||
|
* @param command a MongoDB command, must not be {@literal null}.
|
||||||
|
* @param readPreference read preferences to use, can be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
CommandResult executeCommand(DBObject command, ReadPreference readPreference);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
|
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
|
||||||
*
|
*
|
||||||
@@ -144,9 +161,26 @@ public interface MongoOperations {
|
|||||||
* @param <T> return type
|
* @param <T> return type
|
||||||
* @param action callback that specified the MongoDB actions to perform on the DB instance
|
* @param action callback that specified the MongoDB actions to perform on the DB instance
|
||||||
* @return a result object returned by the action or <tt>null</tt>
|
* @return a result object returned by the action or <tt>null</tt>
|
||||||
|
* @deprecated since 1.7 as the MongoDB Java driver version 3 does not longer support request boundaries via
|
||||||
|
* {@link DB#requestStart()} and {@link DB#requestDone()}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
<T> T executeInSession(DbCallback<T> action);
|
<T> T executeInSession(DbCallback<T> action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the given {@link Query} on the entity collection of the specified {@code entityType} backed by a Mongo DB
|
||||||
|
* {@link Cursor}.
|
||||||
|
* <p>
|
||||||
|
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
|
||||||
|
*
|
||||||
|
* @param <T> element return type
|
||||||
|
* @param query
|
||||||
|
* @param entityType
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
<T> CloseableIterator<T> stream(Query query, Class<T> entityType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an uncapped collection with a name based on the provided entity class.
|
* Create an uncapped collection with a name based on the provided entity class.
|
||||||
*
|
*
|
||||||
@@ -250,6 +284,14 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
IndexOperations indexOps(Class<?> entityClass);
|
IndexOperations indexOps(Class<?> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ScriptOperations} that can be performed on {@link com.mongodb.DB} level.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
ScriptOperations scriptOps();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query for a list of objects of type T from the collection used by the entity class.
|
* Query for a list of objects of type T from the collection used by the entity class.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -416,7 +458,9 @@ public interface MongoOperations {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Will consider entity mapping
|
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Will consider entity mapping
|
||||||
* information to determine the collection the query is ran against.
|
* information to determine the collection the query is ran against. Note, that MongoDB limits the number of results
|
||||||
|
* by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a particular number of
|
||||||
|
* results.
|
||||||
*
|
*
|
||||||
* @param near must not be {@literal null}.
|
* @param near must not be {@literal null}.
|
||||||
* @param entityClass must not be {@literal null}.
|
* @param entityClass must not be {@literal null}.
|
||||||
@@ -425,7 +469,9 @@ public interface MongoOperations {
|
|||||||
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
|
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}.
|
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Note, that MongoDB limits the
|
||||||
|
* number of results by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a
|
||||||
|
* particular number of results.
|
||||||
*
|
*
|
||||||
* @param near must not be {@literal null}.
|
* @param near must not be {@literal null}.
|
||||||
* @param entityClass must not be {@literal null}.
|
* @param entityClass must not be {@literal null}.
|
||||||
@@ -653,14 +699,28 @@ public interface MongoOperations {
|
|||||||
long count(Query query, Class<?> entityClass);
|
long count(Query query, Class<?> entityClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of documents for the given {@link Query} querying the given collection.
|
* Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query}
|
||||||
|
* must solely consist of document field references as we lack type information to map potential property references
|
||||||
|
* onto document fields. TO make sure the query gets mapped, use {@link #count(Query, Class, String)}.
|
||||||
*
|
*
|
||||||
* @param query
|
* @param query
|
||||||
* @param collectionName must not be {@literal null} or empty.
|
* @param collectionName must not be {@literal null} or empty.
|
||||||
* @return
|
* @return
|
||||||
|
* @see #count(Query, Class, String)
|
||||||
*/
|
*/
|
||||||
long count(Query query, String collectionName);
|
long count(Query query, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of documents for the given {@link Query} by querying the given collection using the given entity
|
||||||
|
* class to map the given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param entityClass must not be {@literal null}.
|
||||||
|
* @param collectionName must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
long count(Query query, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the object into the collection for the entity type of the object to save.
|
* Insert the object into the collection for the entity type of the object to save.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -942,4 +1002,5 @@ public interface MongoOperations {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
MongoConverter getConverter();
|
MongoConverter getConverter();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2014 the original author or authors.
|
* Copyright 2010-2015 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,41 +17,48 @@ package org.springframework.data.mongodb.core;
|
|||||||
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||||
|
|
||||||
import com.mongodb.MongoOptions;
|
import com.mongodb.MongoOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory bean for construction of a {@link MongoOptions} instance.
|
* A factory bean for construction of a {@link MongoOptions} instance. In case used with MongoDB Java driver version 3
|
||||||
|
* porperties not suppprted by the driver will be ignored.
|
||||||
*
|
*
|
||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Mike Saavedra
|
* @author Mike Saavedra
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @deprecated since 1.7. Please use {@link MongoClientOptionsFactoryBean} instead.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@Deprecated
|
||||||
public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, InitializingBean {
|
public class MongoOptionsFactoryBean extends AbstractFactoryBean<MongoOptions> {
|
||||||
|
|
||||||
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
|
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
|
||||||
|
|
||||||
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.connectionsPerHost;
|
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
|
||||||
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
|
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
|
||||||
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.maxWaitTime;
|
.getThreadsAllowedToBlockForConnectionMultiplier();
|
||||||
private int connectTimeout = DEFAULT_MONGO_OPTIONS.connectTimeout;
|
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
|
||||||
private int socketTimeout = DEFAULT_MONGO_OPTIONS.socketTimeout;
|
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
|
||||||
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.socketKeepAlive;
|
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
|
||||||
private boolean autoConnectRetry = DEFAULT_MONGO_OPTIONS.autoConnectRetry;
|
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
|
||||||
private long maxAutoConnectRetryTime = DEFAULT_MONGO_OPTIONS.maxAutoConnectRetryTime;
|
private int writeNumber = DEFAULT_MONGO_OPTIONS.getW();
|
||||||
private int writeNumber = DEFAULT_MONGO_OPTIONS.w;
|
private int writeTimeout = DEFAULT_MONGO_OPTIONS.getWtimeout();
|
||||||
private int writeTimeout = DEFAULT_MONGO_OPTIONS.wtimeout;
|
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.isFsync();
|
||||||
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.fsync;
|
|
||||||
private boolean slaveOk = DEFAULT_MONGO_OPTIONS.slaveOk;
|
private boolean autoConnectRetry = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||||
|
.getAutoConnectRetry(DEFAULT_MONGO_OPTIONS) : false;
|
||||||
|
private long maxAutoConnectRetryTime = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||||
|
.getMaxAutoConnectRetryTime(DEFAULT_MONGO_OPTIONS) : -1;
|
||||||
|
private boolean slaveOk = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||||
|
.getSlaveOk(DEFAULT_MONGO_OPTIONS) : false;
|
||||||
|
|
||||||
private boolean ssl;
|
private boolean ssl;
|
||||||
private SSLSocketFactory sslSocketFactory;
|
private SSLSocketFactory sslSocketFactory;
|
||||||
|
|
||||||
private MongoOptions options;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the maximum number of connections allowed per host until we will block.
|
* Configures the maximum number of connections allowed per host until we will block.
|
||||||
*
|
*
|
||||||
@@ -144,7 +151,10 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
|
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @deprecated since 1.7.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
||||||
this.autoConnectRetry = autoConnectRetry;
|
this.autoConnectRetry = autoConnectRetry;
|
||||||
}
|
}
|
||||||
@@ -154,7 +164,9 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
|
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
|
||||||
*
|
*
|
||||||
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
|
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
|
||||||
|
* @deprecated since 1.7
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
|
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
|
||||||
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
||||||
}
|
}
|
||||||
@@ -163,7 +175,9 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
|
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
|
||||||
*
|
*
|
||||||
* @param slaveOk true if the driver should read from secondaries or slaves.
|
* @param slaveOk true if the driver should read from secondaries or slaves.
|
||||||
|
* @deprecated since 1.7
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setSlaveOk(boolean slaveOk) {
|
public void setSlaveOk(boolean slaveOk) {
|
||||||
this.slaveOk = slaveOk;
|
this.slaveOk = slaveOk;
|
||||||
}
|
}
|
||||||
@@ -196,38 +210,39 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||||
*/
|
*/
|
||||||
public void afterPropertiesSet() {
|
@Override
|
||||||
|
protected MongoOptions createInstance() throws Exception {
|
||||||
|
|
||||||
|
if (MongoClientVersion.isMongo3Driver()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String
|
||||||
|
.format("Usage of 'mongo-options' is no longer supported for MongoDB Java driver version 3 and above. Please use 'mongo-client-options' and refer to chapter 'MongoDB 3.0 Support' for details."));
|
||||||
|
}
|
||||||
|
|
||||||
MongoOptions options = new MongoOptions();
|
MongoOptions options = new MongoOptions();
|
||||||
|
|
||||||
options.connectionsPerHost = connectionsPerHost;
|
options.setConnectionsPerHost(connectionsPerHost);
|
||||||
options.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
options.setThreadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
|
||||||
options.maxWaitTime = maxWaitTime;
|
options.setMaxWaitTime(maxWaitTime);
|
||||||
options.connectTimeout = connectTimeout;
|
options.setConnectTimeout(connectTimeout);
|
||||||
options.socketTimeout = socketTimeout;
|
options.setSocketTimeout(socketTimeout);
|
||||||
options.socketKeepAlive = socketKeepAlive;
|
options.setSocketKeepAlive(socketKeepAlive);
|
||||||
options.autoConnectRetry = autoConnectRetry;
|
|
||||||
options.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
options.setW(writeNumber);
|
||||||
options.slaveOk = slaveOk;
|
options.setWtimeout(writeTimeout);
|
||||||
options.w = writeNumber;
|
options.setFsync(writeFsync);
|
||||||
options.wtimeout = writeTimeout;
|
|
||||||
options.fsync = writeFsync;
|
|
||||||
|
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
|
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options = options;
|
ReflectiveMongoOptionsInvoker.setAutoConnectRetry(options, autoConnectRetry);
|
||||||
}
|
ReflectiveMongoOptionsInvoker.setMaxAutoConnectRetryTime(options, maxAutoConnectRetryTime);
|
||||||
|
ReflectiveMongoOptionsInvoker.setSlaveOk(options, slaveOk);
|
||||||
|
|
||||||
/*
|
return options;
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
|
||||||
*/
|
|
||||||
public MongoOptions getObject() {
|
|
||||||
return this.options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -237,12 +252,4 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return MongoOptions.class;
|
return MongoOptions.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
|
||||||
*/
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2014 the original author or authors.
|
* Copyright 2010-2015 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.
|
||||||
@@ -53,9 +53,11 @@ import org.springframework.data.authentication.UserCredentials;
|
|||||||
import org.springframework.data.convert.EntityReader;
|
import org.springframework.data.convert.EntityReader;
|
||||||
import org.springframework.data.geo.Distance;
|
import org.springframework.data.geo.Distance;
|
||||||
import org.springframework.data.geo.GeoResult;
|
import org.springframework.data.geo.GeoResult;
|
||||||
|
import org.springframework.data.geo.GeoResults;
|
||||||
import org.springframework.data.geo.Metric;
|
import org.springframework.data.geo.Metric;
|
||||||
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.BeanWrapper;
|
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||||
@@ -71,7 +73,6 @@ import org.springframework.data.mongodb.core.convert.MongoConverter;
|
|||||||
import org.springframework.data.mongodb.core.convert.MongoWriter;
|
import org.springframework.data.mongodb.core.convert.MongoWriter;
|
||||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||||
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
||||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
|
||||||
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
|
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
|
||||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
@@ -94,14 +95,19 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
|||||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update;
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||||
|
import org.springframework.data.util.CloseableIterator;
|
||||||
import org.springframework.jca.cci.core.ConnectionCallback;
|
import org.springframework.jca.cci.core.ConnectionCallback;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.Bytes;
|
||||||
import com.mongodb.CommandResult;
|
import com.mongodb.CommandResult;
|
||||||
|
import com.mongodb.Cursor;
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
import com.mongodb.DBCursor;
|
import com.mongodb.DBCursor;
|
||||||
@@ -115,6 +121,7 @@ import com.mongodb.WriteConcern;
|
|||||||
import com.mongodb.WriteResult;
|
import com.mongodb.WriteResult;
|
||||||
import com.mongodb.util.JSON;
|
import com.mongodb.util.JSON;
|
||||||
import com.mongodb.util.JSONParseException;
|
import com.mongodb.util.JSONParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary implementation of {@link MongoOperations}.
|
* Primary implementation of {@link MongoOperations}.
|
||||||
*
|
*
|
||||||
@@ -310,6 +317,31 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return this.mongoConverter;
|
return this.mongoConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> CloseableIterator<T> stream(final Query query, final Class<T> entityType) {
|
||||||
|
|
||||||
|
return execute(entityType, new CollectionCallback<CloseableIterator<T>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloseableIterator<T> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
|
|
||||||
|
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
|
||||||
|
|
||||||
|
DBObject mappedFields = queryMapper.getMappedFields(query.getFieldsObject(), persistentEntity);
|
||||||
|
DBObject mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), persistentEntity);
|
||||||
|
|
||||||
|
DBCursor cursor = collection.find(mappedQuery, mappedFields);
|
||||||
|
ReadDbObjectCallback<T> readCallback = new ReadDbObjectCallback<T>(mongoConverter, entityType);
|
||||||
|
|
||||||
|
return new CloseableIterableCusorAdapter<T>(cursor, exceptionTranslator, readCallback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public String getCollectionName(Class<?> entityClass) {
|
public String getCollectionName(Class<?> entityClass) {
|
||||||
return this.determineCollectionName(entityClass);
|
return this.determineCollectionName(entityClass);
|
||||||
}
|
}
|
||||||
@@ -330,15 +362,32 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, int)
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public CommandResult executeCommand(final DBObject command, final int options) {
|
public CommandResult executeCommand(final DBObject command, final int options) {
|
||||||
|
return executeCommand(command, (options & Bytes.QUERYOPTION_SLAVEOK) != 0 ? ReadPreference.secondaryPreferred()
|
||||||
|
: ReadPreference.primary());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, com.mongodb.ReadPreference)
|
||||||
|
*/
|
||||||
|
public CommandResult executeCommand(final DBObject command, final ReadPreference readPreference) {
|
||||||
|
|
||||||
|
Assert.notNull(command, "Command must not be null!");
|
||||||
|
|
||||||
CommandResult result = execute(new DbCallback<CommandResult>() {
|
CommandResult result = execute(new DbCallback<CommandResult>() {
|
||||||
public CommandResult doInDB(DB db) throws MongoException, DataAccessException {
|
public CommandResult doInDB(DB db) throws MongoException, DataAccessException {
|
||||||
return db.command(command, options);
|
return db.command(command, readPreference);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
logCommandExecutionError(command, result);
|
logCommandExecutionError(command, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +403,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch) {
|
public void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch) {
|
||||||
executeQuery(query, collectionName, dch, new QueryCursorPreparer(query));
|
executeQuery(query, collectionName, dch, new QueryCursorPreparer(query, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,14 +461,20 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#executeInSession(org.springframework.data.mongodb.core.DbCallback)
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> T executeInSession(final DbCallback<T> action) {
|
public <T> T executeInSession(final DbCallback<T> action) {
|
||||||
|
|
||||||
return execute(new DbCallback<T>() {
|
return execute(new DbCallback<T>() {
|
||||||
public T doInDB(DB db) throws MongoException, DataAccessException {
|
public T doInDB(DB db) throws MongoException, DataAccessException {
|
||||||
try {
|
try {
|
||||||
db.requestStart();
|
ReflectiveDbInvoker.requestStart(db);
|
||||||
return action.doInDB(db);
|
return action.doInDB(db);
|
||||||
} finally {
|
} finally {
|
||||||
db.requestDone();
|
ReflectiveDbInvoker.requestDone(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -485,6 +540,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
|
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#scriptOps()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ScriptOperations scriptOps() {
|
||||||
|
return new DefaultScriptOperations(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Find methods that take a Query to express the query and that return a single object.
|
// Find methods that take a Query to express the query and that return a single object.
|
||||||
|
|
||||||
public <T> T findOne(Query query, Class<T> entityClass) {
|
public <T> T findOne(Query query, Class<T> entityClass) {
|
||||||
@@ -532,7 +596,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
|
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
|
||||||
new QueryCursorPreparer(query));
|
new QueryCursorPreparer(query, entityClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T findById(Object id, Class<T> entityClass) {
|
public <T> T findById(Object id, Class<T> entityClass) {
|
||||||
@@ -614,8 +678,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
public <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
|
public <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
|
||||||
String collectionName) {
|
String collectionName) {
|
||||||
return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(), query.getSortObject(),
|
return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
|
||||||
entityClass, update, options);
|
getMappedSortObject(query, entityClass), entityClass, update, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find methods that take a Query to express the query and that return a single object that is also removed from the
|
// Find methods that take a Query to express the query and that return a single object that is also removed from the
|
||||||
@@ -626,8 +690,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T findAndRemove(Query query, Class<T> entityClass, String collectionName) {
|
public <T> T findAndRemove(Query query, Class<T> entityClass, String collectionName) {
|
||||||
return doFindAndRemove(collectionName, query.getQueryObject(), query.getFieldsObject(), query.getSortObject(),
|
|
||||||
entityClass);
|
return doFindAndRemove(collectionName, query.getQueryObject(), query.getFieldsObject(),
|
||||||
|
getMappedSortObject(query, entityClass), entityClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long count(Query query, Class<?> entityClass) {
|
public long count(Query query, Class<?> entityClass) {
|
||||||
@@ -639,7 +704,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return count(query, null, collectionName);
|
return count(query, null, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long count(Query query, Class<?> entityClass, String collectionName) {
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||||
|
*/
|
||||||
|
public long count(Query query, Class<?> entityClass, String collectionName) {
|
||||||
|
|
||||||
Assert.hasText(collectionName);
|
Assert.hasText(collectionName);
|
||||||
final DBObject dbObject = query == null ? null : queryMapper.getMappedObject(query.getQueryObject(),
|
final DBObject dbObject = query == null ? null : queryMapper.getMappedObject(query.getQueryObject(),
|
||||||
@@ -692,13 +761,23 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the WriteConcern before any processing is done using it. This allows a convenient way to apply custom
|
* Prepare the WriteConcern before any processing is done using it. This allows a convenient way to apply custom
|
||||||
* settings in sub-classes.
|
* settings in sub-classes. <br />
|
||||||
|
* In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to
|
||||||
|
* {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
|
||||||
*
|
*
|
||||||
* @param writeConcern any WriteConcern already configured or null
|
* @param writeConcern any WriteConcern already configured or null
|
||||||
* @return The prepared WriteConcern or null
|
* @return The prepared WriteConcern or null
|
||||||
*/
|
*/
|
||||||
protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
|
protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
|
||||||
return writeConcernResolver.resolve(mongoAction);
|
|
||||||
|
WriteConcern wc = writeConcernResolver.resolve(mongoAction);
|
||||||
|
|
||||||
|
if (MongoClientVersion.isMongo3Driver()
|
||||||
|
&& ObjectUtils.nullSafeEquals(WriteResultChecking.EXCEPTION, writeResultChecking)
|
||||||
|
&& (wc == null || wc.getW() < 1)) {
|
||||||
|
return WriteConcern.ACKNOWLEDGED;
|
||||||
|
}
|
||||||
|
return wc;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||||
@@ -743,8 +822,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
||||||
|
|
||||||
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
||||||
BeanWrapper<Object> wrapper = BeanWrapper.create(entity, this.mongoConverter.getConversionService());
|
ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(
|
||||||
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
mongoPersistentEntity.getPropertyAccessor(entity), mongoConverter.getConversionService());
|
||||||
|
accessor.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,11 +917,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
private <T> void doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) {
|
private <T> void doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) {
|
||||||
|
|
||||||
BeanWrapper<T> beanWrapper = BeanWrapper.create(objectToSave, this.mongoConverter.getConversionService());
|
ConvertingPropertyAccessor convertingAccessor = new ConvertingPropertyAccessor(
|
||||||
|
entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService());
|
||||||
|
|
||||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||||
MongoPersistentProperty versionProperty = entity.getVersionProperty();
|
MongoPersistentProperty versionProperty = entity.getVersionProperty();
|
||||||
|
|
||||||
Number version = beanWrapper.getProperty(versionProperty, Number.class);
|
Object version = convertingAccessor.getProperty(versionProperty);
|
||||||
|
Number versionNumber = convertingAccessor.getProperty(versionProperty, Number.class);
|
||||||
|
|
||||||
// Fresh instance -> initialize version property
|
// Fresh instance -> initialize version property
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
@@ -851,12 +934,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
assertUpdateableIdIfNotSet(objectToSave);
|
assertUpdateableIdIfNotSet(objectToSave);
|
||||||
|
|
||||||
// Create query for entity with the id and old version
|
// Create query for entity with the id and old version
|
||||||
Object id = beanWrapper.getProperty(idProperty);
|
Object id = convertingAccessor.getProperty(idProperty);
|
||||||
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
|
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
|
||||||
|
|
||||||
// Bump version number
|
// Bump version number
|
||||||
Number number = beanWrapper.getProperty(versionProperty, Number.class);
|
convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1);
|
||||||
beanWrapper.setProperty(versionProperty, number.longValue() + 1);
|
|
||||||
|
|
||||||
BasicDBObject dbObject = new BasicDBObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
@@ -1005,8 +1087,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
update.getUpdateObject(), entity);
|
update.getUpdateObject(), entity);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("Calling update using query: " + queryObj + " and update: " + updateObj + " in collection: "
|
LOGGER.debug(String.format("Calling update using query: %s and update: %s in collection: %s",
|
||||||
+ collectionName);
|
serializeToJsonSafely(queryObj), serializeToJsonSafely(updateObj), collectionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName,
|
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName,
|
||||||
@@ -1016,7 +1098,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
: collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
|
: collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
|
||||||
|
|
||||||
if (entity != null && entity.hasVersionProperty() && !multi) {
|
if (entity != null && entity.hasVersionProperty() && !multi) {
|
||||||
if (writeResult.getN() == 0 && dbObjectContainsVersionProperty(queryObj, entity)) {
|
if (ReflectiveWriteResultInvoker.wasAcknowledged(writeResult) && writeResult.getN() == 0
|
||||||
|
&& dbObjectContainsVersionProperty(queryObj, entity)) {
|
||||||
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
|
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
|
||||||
+ updateObj.toMap().toString() + " to collection " + collectionName);
|
+ updateObj.toMap().toString() + " to collection " + collectionName);
|
||||||
}
|
}
|
||||||
@@ -1068,27 +1151,31 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link Entry} containing the {@link MongoPersistentProperty} defining the {@literal id} as
|
* Returns {@link Entry} containing the field name of the id property as {@link Entry#getKey()} and the {@link Id}s
|
||||||
* {@link Entry#getKey()} and the {@link Id}s property value as its {@link Entry#getValue()}.
|
* property value as its {@link Entry#getValue()}.
|
||||||
*
|
*
|
||||||
* @param object
|
* @param object
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Map.Entry<MongoPersistentProperty, Object> extractIdPropertyAndValue(Object object) {
|
private Entry<String, Object> extractIdPropertyAndValue(Object object) {
|
||||||
|
|
||||||
Assert.notNull(object, "Id cannot be extracted from 'null'.");
|
Assert.notNull(object, "Id cannot be extracted from 'null'.");
|
||||||
|
|
||||||
Class<?> objectType = object.getClass();
|
Class<?> objectType = object.getClass();
|
||||||
|
|
||||||
|
if (object instanceof DBObject) {
|
||||||
|
return Collections.singletonMap(ID_FIELD, ((DBObject) object).get(ID_FIELD)).entrySet().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
||||||
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
||||||
|
|
||||||
if (idProp == null) {
|
if (idProp == null || entity == null) {
|
||||||
throw new MappingException("No id property found for object of type " + objectType);
|
throw new MappingException("No id property found for object of type " + objectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object idValue = BeanWrapper.create(object, mongoConverter.getConversionService())
|
Object idValue = entity.getPropertyAccessor(object).getProperty(idProp);
|
||||||
.getProperty(idProp, Object.class);
|
return Collections.singletonMap(idProp.getFieldName(), idValue).entrySet().iterator().next();
|
||||||
return Collections.singletonMap(idProp, idValue).entrySet().iterator().next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1099,8 +1186,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
*/
|
*/
|
||||||
private Query getIdQueryFor(Object object) {
|
private Query getIdQueryFor(Object object) {
|
||||||
|
|
||||||
Map.Entry<MongoPersistentProperty, Object> id = extractIdPropertyAndValue(object);
|
Entry<String, Object> id = extractIdPropertyAndValue(object);
|
||||||
return new Query(where(id.getKey().getFieldName()).is(id.getValue()));
|
return new Query(where(id.getKey()).is(id.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1114,7 +1201,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
Assert.notEmpty(objects, "Cannot create Query for empty collection.");
|
Assert.notEmpty(objects, "Cannot create Query for empty collection.");
|
||||||
|
|
||||||
Iterator<?> it = objects.iterator();
|
Iterator<?> it = objects.iterator();
|
||||||
Map.Entry<MongoPersistentProperty, Object> firstEntry = extractIdPropertyAndValue(it.next());
|
Entry<String, Object> firstEntry = extractIdPropertyAndValue(it.next());
|
||||||
|
|
||||||
ArrayList<Object> ids = new ArrayList<Object>(objects.size());
|
ArrayList<Object> ids = new ArrayList<Object>(objects.size());
|
||||||
ids.add(firstEntry.getValue());
|
ids.add(firstEntry.getValue());
|
||||||
@@ -1123,7 +1210,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
ids.add(extractIdPropertyAndValue(it.next()).getValue());
|
ids.add(extractIdPropertyAndValue(it.next()).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Query(where(firstEntry.getKey().getFieldName()).in(ids));
|
return new Query(where(firstEntry.getKey()).in(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertUpdateableIdIfNotSet(Object entity) {
|
private void assertUpdateableIdIfNotSet(Object entity) {
|
||||||
@@ -1131,12 +1218,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entity.getClass());
|
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entity.getClass());
|
||||||
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
|
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
|
||||||
|
|
||||||
if (idProperty == null) {
|
if (idProperty == null || persistentEntity == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionService service = mongoConverter.getConversionService();
|
Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty);
|
||||||
Object idValue = BeanWrapper.create(entity, service).getProperty(idProperty, Object.class);
|
|
||||||
|
|
||||||
if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
|
if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
|
||||||
throw new InvalidDataAccessApiUsageException(String.format(
|
throw new InvalidDataAccessApiUsageException(String.format(
|
||||||
@@ -1180,7 +1266,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("Remove using query: {} in collection: {}.", new Object[] { dboq, collection.getName() });
|
LOGGER.debug("Remove using query: {} in collection: {}.", new Object[] { serializeToJsonSafely(dboq),
|
||||||
|
collection.getName() });
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
|
WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
|
||||||
@@ -1228,25 +1315,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
|
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
|
||||||
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
|
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
|
||||||
DBCollection inputCollection = getCollection(inputCollectionName);
|
DBCollection inputCollection = getCollection(inputCollectionName);
|
||||||
MapReduceCommand command = new MapReduceCommand(inputCollection, mapFunc, reduceFunc,
|
|
||||||
mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), null);
|
|
||||||
|
|
||||||
DBObject commandObject = copyQuery(query, copyMapReduceOptions(mapReduceOptions, command));
|
MapReduceCommand command = new MapReduceCommand(inputCollection, mapFunc, reduceFunc,
|
||||||
|
mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), query == null
|
||||||
|
|| query.getQueryObject() == null ? null : queryMapper.getMappedObject(query.getQueryObject(), null));
|
||||||
|
|
||||||
|
copyMapReduceOptionsToCommand(query, mapReduceOptions, command);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc
|
LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc
|
||||||
+ "], reduceFunction [" + reduceFunc + "]");
|
+ "], reduceFunction [" + reduceFunc + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult commandResult = command.getOutputType() == MapReduceCommand.OutputType.INLINE ? executeCommand(
|
MapReduceOutput mapReduceOutput = inputCollection.mapReduce(command);
|
||||||
commandObject, getDb().getOptions()) : executeCommand(commandObject);
|
|
||||||
handleCommandError(commandResult, commandObject);
|
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(commandObject));
|
LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(mapReduceOutput.results()));
|
||||||
}
|
}
|
||||||
|
|
||||||
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
|
|
||||||
List<T> mappedResults = new ArrayList<T>();
|
List<T> mappedResults = new ArrayList<T>();
|
||||||
DbObjectCallback<T> callback = new ReadDbObjectCallback<T>(mongoConverter, entityClass);
|
DbObjectCallback<T> callback = new ReadDbObjectCallback<T>(mongoConverter, entityClass);
|
||||||
|
|
||||||
@@ -1254,7 +1340,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
mappedResults.add(callback.doWith(dbObject));
|
mappedResults.add(callback.doWith(dbObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MapReduceResults<T>(mappedResults, commandResult);
|
return new MapReduceResults<T>(mappedResults, mapReduceOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> GroupByResults<T> group(String inputCollectionName, GroupBy groupBy, Class<T> entityClass) {
|
public <T> GroupByResults<T> group(String inputCollectionName, GroupBy groupBy, Class<T> entityClass) {
|
||||||
@@ -1411,17 +1497,32 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
CommandResult commandResult = executeCommand(command);
|
CommandResult commandResult = executeCommand(command);
|
||||||
handleCommandError(commandResult, command);
|
handleCommandError(commandResult, command);
|
||||||
|
|
||||||
// map results
|
return new AggregationResults<O>(returnPotentiallyMappedResults(outputType, commandResult), commandResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the potentially mapped results of the given {@commandResult} contained some.
|
||||||
|
*
|
||||||
|
* @param outputType
|
||||||
|
* @param commandResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private <O> List<O> returnPotentiallyMappedResults(Class<O> outputType, CommandResult commandResult) {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Iterable<DBObject> resultSet = (Iterable<DBObject>) commandResult.get("result");
|
Iterable<DBObject> resultSet = (Iterable<DBObject>) commandResult.get("result");
|
||||||
List<O> mappedResults = new ArrayList<O>();
|
if (resultSet == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
DbObjectCallback<O> callback = new UnwrapAndReadDbObjectCallback<O>(mongoConverter, outputType);
|
DbObjectCallback<O> callback = new UnwrapAndReadDbObjectCallback<O>(mongoConverter, outputType);
|
||||||
|
|
||||||
|
List<O> mappedResults = new ArrayList<O>();
|
||||||
for (DBObject dbObject : resultSet) {
|
for (DBObject dbObject : resultSet) {
|
||||||
mappedResults.add(callback.doWith(dbObject));
|
mappedResults.add(callback.doWith(dbObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AggregationResults<O>(mappedResults, commandResult);
|
return mappedResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String replaceWithResourceIfNecessary(String function) {
|
protected String replaceWithResourceIfNecessary(String function) {
|
||||||
@@ -1446,51 +1547,40 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DBObject copyQuery(Query query, DBObject copyMapReduceOptions) {
|
private void copyMapReduceOptionsToCommand(Query query, MapReduceOptions mapReduceOptions,
|
||||||
|
MapReduceCommand mapReduceCommand) {
|
||||||
|
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
if (query.getSkip() != 0 || query.getFieldsObject() != null) {
|
if (query.getSkip() != 0 || query.getFieldsObject() != null) {
|
||||||
throw new InvalidDataAccessApiUsageException(
|
throw new InvalidDataAccessApiUsageException(
|
||||||
"Can not use skip or field specification with map reduce operations");
|
"Can not use skip or field specification with map reduce operations");
|
||||||
}
|
}
|
||||||
if (query.getQueryObject() != null) {
|
|
||||||
copyMapReduceOptions.put("query", query.getQueryObject());
|
|
||||||
}
|
|
||||||
if (query.getLimit() > 0) {
|
if (query.getLimit() > 0) {
|
||||||
copyMapReduceOptions.put("limit", query.getLimit());
|
mapReduceCommand.setLimit(query.getLimit());
|
||||||
}
|
}
|
||||||
if (query.getSortObject() != null) {
|
if (query.getSortObject() != null) {
|
||||||
copyMapReduceOptions.put("sort", query.getSortObject());
|
mapReduceCommand.setSort(queryMapper.getMappedObject(query.getSortObject(), null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return copyMapReduceOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DBObject copyMapReduceOptions(MapReduceOptions mapReduceOptions, MapReduceCommand command) {
|
|
||||||
if (mapReduceOptions.getJavaScriptMode() != null) {
|
if (mapReduceOptions.getJavaScriptMode() != null) {
|
||||||
command.addExtraOption("jsMode", true);
|
mapReduceCommand.setJsMode(true);
|
||||||
}
|
}
|
||||||
if (!mapReduceOptions.getExtraOptions().isEmpty()) {
|
if (!mapReduceOptions.getExtraOptions().isEmpty()) {
|
||||||
for (Map.Entry<String, Object> entry : mapReduceOptions.getExtraOptions().entrySet()) {
|
for (Map.Entry<String, Object> entry : mapReduceOptions.getExtraOptions().entrySet()) {
|
||||||
command.addExtraOption(entry.getKey(), entry.getValue());
|
ReflectiveMapReduceInvoker.addExtraOption(mapReduceCommand, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mapReduceOptions.getFinalizeFunction() != null) {
|
if (mapReduceOptions.getFinalizeFunction() != null) {
|
||||||
command.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
|
mapReduceCommand.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
|
||||||
}
|
}
|
||||||
if (mapReduceOptions.getOutputDatabase() != null) {
|
if (mapReduceOptions.getOutputDatabase() != null) {
|
||||||
command.setOutputDB(mapReduceOptions.getOutputDatabase());
|
mapReduceCommand.setOutputDB(mapReduceOptions.getOutputDatabase());
|
||||||
}
|
}
|
||||||
if (!mapReduceOptions.getScopeVariables().isEmpty()) {
|
if (!mapReduceOptions.getScopeVariables().isEmpty()) {
|
||||||
command.setScope(mapReduceOptions.getScopeVariables());
|
mapReduceCommand.setScope(mapReduceOptions.getScopeVariables());
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject commandObject = command.toDBObject();
|
|
||||||
DBObject outObject = (DBObject) commandObject.get("out");
|
|
||||||
|
|
||||||
if (mapReduceOptions.getOutputSharded() != null) {
|
|
||||||
outObject.put("sharded", mapReduceOptions.getOutputSharded());
|
|
||||||
}
|
|
||||||
return commandObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getCollectionNames() {
|
public Set<String> getCollectionNames() {
|
||||||
@@ -1594,12 +1684,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
CursorPreparer preparer, DbObjectCallback<T> objectCallback) {
|
CursorPreparer preparer, DbObjectCallback<T> objectCallback) {
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||||
DBObject mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
|
|
||||||
|
DBObject mappedFields = queryMapper.getMappedFields(fields, entity);
|
||||||
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
|
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
|
LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
|
||||||
serializeToJsonSafely(query), mappedFields, entityClass, collectionName));
|
serializeToJsonSafely(mappedQuery), mappedFields, entityClass, collectionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return executeFindMultiInternal(new FindCallback(mappedQuery, mappedFields), preparer, objectCallback,
|
return executeFindMultiInternal(new FindCallback(mappedQuery, mappedFields), preparer, objectCallback,
|
||||||
@@ -1637,8 +1728,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
Class<T> entityClass) {
|
Class<T> entityClass) {
|
||||||
EntityReader<? super T, DBObject> readerToUse = this.mongoConverter;
|
EntityReader<? super T, DBObject> readerToUse = this.mongoConverter;
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("findAndRemove using query: " + query + " fields: " + fields + " sort: " + sort + " for class: "
|
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
|
||||||
+ entityClass + " in collection: " + collectionName);
|
serializeToJsonSafely(query), fields, sort, entityClass, collectionName));
|
||||||
}
|
}
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||||
return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort),
|
return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort),
|
||||||
@@ -1662,8 +1753,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
DBObject mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
|
DBObject mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort
|
LOGGER.debug(String.format("findAndModify using query: %s fields: %s sort: %s for class: %s and update: %s "
|
||||||
+ " for class: " + entityClass + " and update: " + mappedUpdate + " in collection: " + collectionName);
|
+ "in collection: %s", serializeToJsonSafely(mappedQuery), fields, sort, entityClass,
|
||||||
|
serializeToJsonSafely(mappedUpdate), collectionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
|
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
|
||||||
@@ -1695,15 +1787,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConversionService conversionService = mongoConverter.getConversionService();
|
ConversionService conversionService = mongoConverter.getConversionService();
|
||||||
BeanWrapper<Object> wrapper = BeanWrapper.create(savedObject, conversionService);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(savedObject.getClass());
|
||||||
|
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject);
|
||||||
|
|
||||||
Object idValue = wrapper.getProperty(idProp, idProp.getType());
|
if (accessor.getProperty(idProp) != null) {
|
||||||
|
|
||||||
if (idValue != null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper.setProperty(idProp, id);
|
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DBCollection getAndPrepareCollection(DB db, String collectionName) {
|
private DBCollection getAndPrepareCollection(DB db, String collectionName) {
|
||||||
@@ -1870,7 +1961,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String error = writeResult.getError();
|
String error = ReflectiveWriteResultInvoker.getError(writeResult);
|
||||||
|
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
return;
|
return;
|
||||||
@@ -1941,6 +2032,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DBObject getMappedSortObject(Query query, Class<?> type) {
|
||||||
|
|
||||||
|
if (query == null || query.getSortObject() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryMapper.getMappedSort(query.getSortObject(), mappingContext.getPersistentEntity(type));
|
||||||
|
}
|
||||||
|
|
||||||
// Callback implementations
|
// Callback implementations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1963,13 +2063,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
if (fields == null) {
|
if (fields == null) {
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("findOne using query: " + query + " in db.collection: " + collection.getFullName());
|
LOGGER.debug(String.format("findOne using query: %s in db.collection: %s", serializeToJsonSafely(query),
|
||||||
|
collection.getFullName()));
|
||||||
}
|
}
|
||||||
return collection.findOne(query);
|
return collection.findOne(query);
|
||||||
} else {
|
} else {
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("findOne using query: " + query + " fields: " + fields + " in db.collection: "
|
LOGGER.debug(String.format("findOne using query: %s fields: %s in db.collection: %s",
|
||||||
+ collection.getFullName());
|
serializeToJsonSafely(query), fields, collection.getFullName()));
|
||||||
}
|
}
|
||||||
return collection.findOne(query, fields);
|
return collection.findOne(query, fields);
|
||||||
}
|
}
|
||||||
@@ -1998,7 +2099,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DBCursor doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public DBCursor doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
if (fields == null) {
|
|
||||||
|
if (fields == null || fields.toMap().isEmpty()) {
|
||||||
return collection.find(query);
|
return collection.find(query);
|
||||||
} else {
|
} else {
|
||||||
return collection.find(query, fields);
|
return collection.find(query, fields);
|
||||||
@@ -2056,9 +2158,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
* Simple internal callback to allow operations on a {@link DBObject}.
|
* Simple internal callback to allow operations on a {@link DBObject}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private interface DbObjectCallback<T> {
|
static interface DbObjectCallback<T> {
|
||||||
|
|
||||||
T doWith(DBObject object);
|
T doWith(DBObject object);
|
||||||
}
|
}
|
||||||
@@ -2134,9 +2237,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
class QueryCursorPreparer implements CursorPreparer {
|
class QueryCursorPreparer implements CursorPreparer {
|
||||||
|
|
||||||
private final Query query;
|
private final Query query;
|
||||||
|
private final Class<?> type;
|
||||||
|
|
||||||
|
public QueryCursorPreparer(Query query, Class<?> type) {
|
||||||
|
|
||||||
public QueryCursorPreparer(Query query) {
|
|
||||||
this.query = query;
|
this.query = query;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2150,11 +2256,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (query.getSkip() <= 0 && query.getLimit() <= 0 && query.getSortObject() == null
|
if (query.getSkip() <= 0 && query.getLimit() <= 0 && query.getSortObject() == null
|
||||||
&& !StringUtils.hasText(query.getHint())) {
|
&& !StringUtils.hasText(query.getHint()) && !query.getMeta().hasValues()) {
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBCursor cursorToUse = cursor;
|
DBCursor cursorToUse = cursor.copy();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (query.getSkip() > 0) {
|
if (query.getSkip() > 0) {
|
||||||
@@ -2164,11 +2270,18 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
cursorToUse = cursorToUse.limit(query.getLimit());
|
cursorToUse = cursorToUse.limit(query.getLimit());
|
||||||
}
|
}
|
||||||
if (query.getSortObject() != null) {
|
if (query.getSortObject() != null) {
|
||||||
cursorToUse = cursorToUse.sort(query.getSortObject());
|
DBObject sortDbo = type != null ? getMappedSortObject(query, type) : query.getSortObject();
|
||||||
|
cursorToUse = cursorToUse.sort(sortDbo);
|
||||||
}
|
}
|
||||||
if (StringUtils.hasText(query.getHint())) {
|
if (StringUtils.hasText(query.getHint())) {
|
||||||
cursorToUse = cursorToUse.hint(query.getHint());
|
cursorToUse = cursorToUse.hint(query.getHint());
|
||||||
}
|
}
|
||||||
|
if (query.getMeta().hasValues()) {
|
||||||
|
for (Entry<String, Object> entry : query.getMeta().values()) {
|
||||||
|
cursorToUse = cursorToUse.addSpecial(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw potentiallyConvertRuntimeException(e);
|
throw potentiallyConvertRuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -2211,4 +2324,76 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link CloseableIterator} that is backed by a MongoDB {@link Cursor}.
|
||||||
|
*
|
||||||
|
* @since 1.7
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
static class CloseableIterableCusorAdapter<T> implements CloseableIterator<T> {
|
||||||
|
|
||||||
|
private volatile Cursor cursor;
|
||||||
|
private PersistenceExceptionTranslator exceptionTranslator;
|
||||||
|
private DbObjectCallback<T> objectReadCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link CloseableIterableCusorAdapter} backed by the given {@link Cursor}.
|
||||||
|
*
|
||||||
|
* @param cursor
|
||||||
|
* @param exceptionTranslator
|
||||||
|
* @param objectReadCallback
|
||||||
|
*/
|
||||||
|
public CloseableIterableCusorAdapter(Cursor cursor, PersistenceExceptionTranslator exceptionTranslator,
|
||||||
|
DbObjectCallback<T> objectReadCallback) {
|
||||||
|
|
||||||
|
this.cursor = cursor;
|
||||||
|
this.exceptionTranslator = exceptionTranslator;
|
||||||
|
this.objectReadCallback = objectReadCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
|
||||||
|
if (cursor == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cursor.hasNext();
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw exceptionTranslator.translateExceptionIfPossible(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
|
||||||
|
if (cursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DBObject item = cursor.next();
|
||||||
|
T converted = objectReadCallback.doWith(item);
|
||||||
|
return converted;
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw exceptionTranslator.translateExceptionIfPossible(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
Cursor c = cursor;
|
||||||
|
try {
|
||||||
|
c.close();
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw exceptionTranslator.translateExceptionIfPossible(ex);
|
||||||
|
} finally {
|
||||||
|
cursor = null;
|
||||||
|
exceptionTranslator = null;
|
||||||
|
objectReadCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||||
|
|
||||||
|
import com.mongodb.DBCollection;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveDBCollectionInvoker} provides reflective access to {@link DBCollection} API that is not consistently
|
||||||
|
* available for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
class ReflectiveDBCollectionInvoker {
|
||||||
|
|
||||||
|
private static final Method GEN_INDEX_NAME_METHOD;
|
||||||
|
private static final Method RESET_INDEX_CHACHE_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", DBObject.class);
|
||||||
|
RESET_INDEX_CHACHE_METHOD = findMethod(DBCollection.class, "resetIndexCache");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectiveDBCollectionInvoker() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to generate an index name from the set of fields it is over. Will fall back to a MongoDB Java
|
||||||
|
* driver version 2 compatible way of generating index name in case of {@link MongoClientVersion#isMongo3Driver()}.
|
||||||
|
*
|
||||||
|
* @param keys the names of the fields used in this index
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String generateIndexName(DBObject keys) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return genIndexName(keys);
|
||||||
|
}
|
||||||
|
return (String) invokeMethod(GEN_INDEX_NAME_METHOD, null, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case of MongoDB Java driver version 2 all indices that have not yet been applied to this collection will be
|
||||||
|
* cleared. Since this method is not available for the MongoDB Java driver version 3 the operation will throw
|
||||||
|
* {@link UnsupportedOperationException}.
|
||||||
|
*
|
||||||
|
* @param dbCollection
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public static void resetIndexCache(DBCollection dbCollection) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
throw new UnsupportedOperationException("The mongo java driver 3 does no loger support resetIndexCache!");
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(RESET_INDEX_CHACHE_METHOD, dbCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Borrowed from MongoDB Java driver version 2. See <a
|
||||||
|
* href="http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754"
|
||||||
|
* >http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754</a>
|
||||||
|
*
|
||||||
|
* @param keys
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String genIndexName(DBObject keys) {
|
||||||
|
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
|
||||||
|
for (String s : keys.keySet()) {
|
||||||
|
|
||||||
|
if (name.length() > 0) {
|
||||||
|
name.append('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
name.append(s).append('_');
|
||||||
|
Object val = keys.get(s);
|
||||||
|
|
||||||
|
if (val instanceof Number || val instanceof String) {
|
||||||
|
name.append(val.toString().replace(' ', '_'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
|
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||||
|
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveDbInvoker} provides reflective access to {@link DB} API that is not consistently available for
|
||||||
|
* various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
final class ReflectiveDbInvoker {
|
||||||
|
|
||||||
|
private static final Method DB_IS_AUTHENTICATED_METHOD;
|
||||||
|
private static final Method DB_AUTHENTICATE_METHOD;
|
||||||
|
private static final Method DB_REQUEST_DONE_METHOD;
|
||||||
|
private static final Method DB_ADD_USER_METHOD;
|
||||||
|
private static final Method DB_REQUEST_START_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
DB_IS_AUTHENTICATED_METHOD = findMethod(DB.class, "isAuthenticated");
|
||||||
|
DB_AUTHENTICATE_METHOD = findMethod(DB.class, "authenticate", String.class, char[].class);
|
||||||
|
DB_REQUEST_DONE_METHOD = findMethod(DB.class, "requestDone");
|
||||||
|
DB_ADD_USER_METHOD = findMethod(DB.class, "addUser", String.class, char[].class);
|
||||||
|
DB_REQUEST_START_METHOD = findMethod(DB.class, "requestStart");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectiveDbInvoker() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate against database using provided credentials in case of a MongoDB Java driver version 2.
|
||||||
|
*
|
||||||
|
* @param mongo must not be {@literal null}.
|
||||||
|
* @param db must not be {@literal null}.
|
||||||
|
* @param credentials must not be {@literal null}.
|
||||||
|
* @param authenticationDatabaseName
|
||||||
|
*/
|
||||||
|
public static void authenticate(Mongo mongo, DB db, UserCredentials credentials, String authenticationDatabaseName) {
|
||||||
|
|
||||||
|
String databaseName = db.getName();
|
||||||
|
|
||||||
|
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
||||||
|
|
||||||
|
synchronized (authDb) {
|
||||||
|
|
||||||
|
Boolean isAuthenticated = (Boolean) invokeMethod(DB_IS_AUTHENTICATED_METHOD, authDb);
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
|
||||||
|
String username = credentials.getUsername();
|
||||||
|
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
||||||
|
|
||||||
|
Boolean authenticated = (Boolean) invokeMethod(DB_AUTHENTICATE_METHOD, authDb, username,
|
||||||
|
password == null ? null : password.toCharArray());
|
||||||
|
if (!authenticated) {
|
||||||
|
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
||||||
|
+ credentials.toString(), databaseName, credentials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new 'consistent request' in case of MongoDB Java driver version 2. Will do nothing for MongoDB Java driver
|
||||||
|
* version 3 since the operation is no longer available.
|
||||||
|
*
|
||||||
|
* @param db
|
||||||
|
*/
|
||||||
|
public static void requestStart(DB db) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(DB_REQUEST_START_METHOD, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the current 'consistent request'. a new 'consistent request' in case of MongoDB Java driver version 2. Will do
|
||||||
|
* nothing for MongoDB Java driver version 3 since the operation is no longer available
|
||||||
|
*
|
||||||
|
* @param db
|
||||||
|
*/
|
||||||
|
public static void requestDone(DB db) {
|
||||||
|
|
||||||
|
if (MongoClientVersion.isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(DB_REQUEST_DONE_METHOD, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param db
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public static void addUser(DB db, String username, char[] password) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Please use DB.command(…) to call either the createUser or updateUser command!");
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(DB_ADD_USER_METHOD, db, username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.MapReduceCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveMapReduceInvoker} provides reflective access to {@link MapReduceCommand} API that is not
|
||||||
|
* consistently available for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
final class ReflectiveMapReduceInvoker {
|
||||||
|
|
||||||
|
private static final Method ADD_EXTRA_OPTION_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
ADD_EXTRA_OPTION_METHOD = findMethod(MapReduceCommand.class, "addExtraOption", String.class, Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectiveMapReduceInvoker() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the extra option for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 2.
|
||||||
|
*
|
||||||
|
* @param cmd can be {@literal null} for MongoDB Java driver version 2.
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public static void addExtraOption(MapReduceCommand cmd, String key, Object value) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.notNull(cmd, "MapReduceCommand must not be null!");
|
||||||
|
invokeMethod(ADD_EXTRA_OPTION_METHOD, cmd, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import com.mongodb.MongoOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveMongoOptionsInvoker} provides reflective access to {@link MongoOptions} API that is not consistently
|
||||||
|
* available for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
class ReflectiveMongoOptionsInvoker {
|
||||||
|
|
||||||
|
private static final Method GET_AUTO_CONNECT_RETRY_METHOD;
|
||||||
|
private static final Method SET_AUTO_CONNECT_RETRY_METHOD;
|
||||||
|
private static final Method GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||||
|
private static final Method SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
SET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils
|
||||||
|
.findMethod(MongoOptions.class, "setAutoConnectRetry", boolean.class);
|
||||||
|
GET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils.findMethod(MongoOptions.class, "isAutoConnectRetry");
|
||||||
|
SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||||
|
"setMaxAutoConnectRetryTime", long.class);
|
||||||
|
GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||||
|
"getMaxAutoConnectRetryTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectiveMongoOptionsInvoker() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the retry connection flag for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||||
|
* since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @param autoConnectRetry
|
||||||
|
*/
|
||||||
|
public static void setAutoConnectRetry(MongoOptions options, boolean autoConnectRetry) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(SET_AUTO_CONNECT_RETRY_METHOD, options, autoConnectRetry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java
|
||||||
|
* driver version 3 since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @param maxAutoConnectRetryTime
|
||||||
|
*/
|
||||||
|
public static void setMaxAutoConnectRetryTime(MongoOptions options, long maxAutoConnectRetryTime) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethod(SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options, maxAutoConnectRetryTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the slaveOk attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||||
|
* since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @param slaveOk
|
||||||
|
*/
|
||||||
|
public static void setSlaveOk(MongoOptions options, boolean slaveOk) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new DirectFieldAccessor(options).setPropertyValue("slaveOk", slaveOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the slaveOk attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException} for
|
||||||
|
* MongoDB Java driver version 3 since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @return
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public static boolean getSlaveOk(MongoOptions options) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Boolean) new DirectFieldAccessor(options).getPropertyValue("slaveOk")).booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the autoConnectRetry attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException}
|
||||||
|
* for MongoDB Java driver version 3 since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @return
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public static boolean getAutoConnectRetry(MongoOptions options) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Boolean) invokeMethod(GET_AUTO_CONNECT_RETRY_METHOD, options)).booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Throws
|
||||||
|
* {@link UnsupportedOperationException} for MongoDB Java driver version 3 since the method has been removed.
|
||||||
|
*
|
||||||
|
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @return
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public static long getMaxAutoConnectRetryTime(MongoOptions options) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Cannot get value for maxAutoConnectRetryTime which has been removed in MongoDB Java driver version 3.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Long) invokeMethod(GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options)).longValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
|
||||||
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
|
|
||||||
|
import com.mongodb.WriteConcern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveWriteConcernInvoker} provides reflective access to {@link WriteConcern} API that is not consistently
|
||||||
|
* available for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
class ReflectiveWriteConcernInvoker {
|
||||||
|
|
||||||
|
private static final WriteConcern NONE_OR_UNACKNOWLEDGED;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
NONE_OR_UNACKNOWLEDGED = isMongo3Driver() ? WriteConcern.UNACKNOWLEDGED : (WriteConcern) new DirectFieldAccessor(
|
||||||
|
new WriteConcern()).getPropertyValue("NONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@link WriteConcern#NONE} for MongoDB Java driver version 2, otherwise {@link WriteConcern#UNACKNOWLEDGED}.
|
||||||
|
*/
|
||||||
|
public static WriteConcern noneOrUnacknowledged() {
|
||||||
|
return NONE_OR_UNACKNOWLEDGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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 static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import com.mongodb.MongoException;
|
||||||
|
import com.mongodb.WriteResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveWriteResultInvoker} provides reflective access to {@link WriteResult} API that is not consistently
|
||||||
|
* available for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
final class ReflectiveWriteResultInvoker {
|
||||||
|
|
||||||
|
private static final Method GET_ERROR_METHOD;
|
||||||
|
private static final Method WAS_ACKNOWLEDGED_METHOD;
|
||||||
|
|
||||||
|
private ReflectiveWriteResultInvoker() {}
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
GET_ERROR_METHOD = findMethod(WriteResult.class, "getError");
|
||||||
|
WAS_ACKNOWLEDGED_METHOD = findMethod(WriteResult.class, "wasAcknowledged");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param writeResult can be {@literal null} for MongoDB Java driver version 3.
|
||||||
|
* @return null in case of MongoDB Java driver version 3 since errors are thrown as {@link MongoException}.
|
||||||
|
*/
|
||||||
|
public static String getError(WriteResult writeResult) {
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String) invokeMethod(GET_ERROR_METHOD, writeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param writeResult
|
||||||
|
* @return return in case of MongoDB Java driver version 2.
|
||||||
|
*/
|
||||||
|
public static boolean wasAcknowledged(WriteResult writeResult) {
|
||||||
|
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD, writeResult)).booleanValue() : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2015 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
|
||||||
|
*
|
||||||
|
* http://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.Set;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||||
|
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script operations on {@link com.mongodb.DB} level. Allows interaction with server side JavaScript functions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public interface ScriptOperations {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store given {@link ExecutableMongoScript} generating a syntheitcal name so that it can be called by it
|
||||||
|
* subsequently.
|
||||||
|
*
|
||||||
|
* @param script must not be {@literal null}.
|
||||||
|
* @return {@link NamedMongoScript} with name under which the {@code JavaScript} function can be called.
|
||||||
|
*/
|
||||||
|
NamedMongoScript register(ExecutableMongoScript script);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given {@link NamedMongoScript} in the database.
|
||||||
|
*
|
||||||
|
* @param script the {@link NamedMongoScript} to be registered.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
NamedMongoScript register(NamedMongoScript script);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the {@literal script} by either calling it via its {@literal name} or directly sending it.
|
||||||
|
*
|
||||||
|
* @param script must not be {@literal null}.
|
||||||
|
* @param args arguments to pass on for script execution.
|
||||||
|
* @return the script evaluation result.
|
||||||
|
* @throws org.springframework.dao.DataAccessException
|
||||||
|
*/
|
||||||
|
Object execute(ExecutableMongoScript script, Object... args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the {@literal JavaScript} by its name.
|
||||||
|
*
|
||||||
|
* @param scriptName must not be {@literal null} or empty.
|
||||||
|
* @param args
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object call(String scriptName, Object... args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks {@link DB} for existence of {@link ServerSideJavaScript} with given name.
|
||||||
|
*
|
||||||
|
* @param scriptName must not be {@literal null} or empty.
|
||||||
|
* @return false if no {@link ServerSideJavaScript} with given name exists.
|
||||||
|
*/
|
||||||
|
boolean exists(String scriptName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns names of {@literal JavaScript} functions that can be called.
|
||||||
|
*
|
||||||
|
* @return empty {@link Set} if no scripts found.
|
||||||
|
*/
|
||||||
|
Set<String> getScriptNames();
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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,6 +27,8 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoClientURI;
|
||||||
import com.mongodb.MongoException;
|
import com.mongodb.MongoException;
|
||||||
import com.mongodb.MongoURI;
|
import com.mongodb.MongoURI;
|
||||||
import com.mongodb.WriteConcern;
|
import com.mongodb.WriteConcern;
|
||||||
@@ -37,6 +39,7 @@ import com.mongodb.WriteConcern;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||||
|
|
||||||
@@ -54,7 +57,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
*
|
*
|
||||||
* @param mongo Mongo instance, must not be {@literal null}.
|
* @param mongo Mongo instance, must not be {@literal null}.
|
||||||
* @param databaseName database name, not be {@literal null} or empty.
|
* @param databaseName database name, not be {@literal null} or empty.
|
||||||
|
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClient, String)}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
||||||
this(mongo, databaseName, null);
|
this(mongo, databaseName, null);
|
||||||
}
|
}
|
||||||
@@ -65,7 +70,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @param mongo Mongo instance, must not be {@literal null}.
|
* @param mongo Mongo instance, must not be {@literal null}.
|
||||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||||
* @param credentials username and password.
|
* @param credentials username and password.
|
||||||
|
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||||
this(mongo, databaseName, credentials, false, null);
|
this(mongo, databaseName, credentials, false, null);
|
||||||
}
|
}
|
||||||
@@ -77,7 +84,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||||
* @param credentials username and password.
|
* @param credentials username and password.
|
||||||
* @param authenticationDatabaseName the database name to use for authentication
|
* @param authenticationDatabaseName the database name to use for authentication
|
||||||
|
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
String authenticationDatabaseName) {
|
String authenticationDatabaseName) {
|
||||||
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
|
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
|
||||||
@@ -90,13 +99,36 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @throws MongoException
|
* @throws MongoException
|
||||||
* @throws UnknownHostException
|
* @throws UnknownHostException
|
||||||
* @see MongoURI
|
* @see MongoURI
|
||||||
|
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClientURI)} instead.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@Deprecated
|
||||||
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
|
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
|
||||||
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
|
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
|
||||||
true, uri.getDatabase());
|
true, uri.getDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
|
||||||
|
*
|
||||||
|
* @param uri must not be {@literal null}.
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
|
||||||
|
this(new MongoClient(uri), uri.getDatabase(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClient}.
|
||||||
|
*
|
||||||
|
* @param mongoClient must not be {@literal null}.
|
||||||
|
* @param databaseName must not be {@literal null}.
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public SimpleMongoDbFactory(MongoClient mongoClient, String databaseName) {
|
||||||
|
this(mongoClient, databaseName, false);
|
||||||
|
}
|
||||||
|
|
||||||
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
boolean mongoInstanceCreated, String authenticationDatabaseName) {
|
boolean mongoInstanceCreated, String authenticationDatabaseName) {
|
||||||
|
|
||||||
@@ -117,6 +149,25 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
"Authentication database name must only contain letters, numbers, underscores and dashes!");
|
"Authentication database name must only contain letters, numbers, underscores and dashes!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param client
|
||||||
|
* @param databaseName
|
||||||
|
* @param mongoInstanceCreated
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
|
||||||
|
|
||||||
|
Assert.notNull(client, "MongoClient must not be null!");
|
||||||
|
Assert.hasText(databaseName, "Database name must not be empty!");
|
||||||
|
|
||||||
|
this.mongo = client;
|
||||||
|
this.databaseName = databaseName;
|
||||||
|
this.mongoInstanceCreated = mongoInstanceCreated;
|
||||||
|
this.exceptionTranslator = new MongoExceptionTranslator();
|
||||||
|
this.credentials = UserCredentials.NO_CREDENTIALS;
|
||||||
|
this.authenticationDatabaseName = databaseName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.
|
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.
|
||||||
*
|
*
|
||||||
@@ -138,6 +189,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.MongoDbFactory#getDb(java.lang.String)
|
* @see org.springframework.data.mongodb.MongoDbFactory#getDb(java.lang.String)
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public DB getDb(String dbName) throws DataAccessException {
|
public DB getDb(String dbName) throws DataAccessException {
|
||||||
|
|
||||||
Assert.hasText(dbName, "Database name must not be empty.");
|
Assert.hasText(dbName, "Database name must not be empty.");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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,6 +27,7 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedFi
|
|||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||||
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -44,9 +45,23 @@ import com.mongodb.DBObject;
|
|||||||
*/
|
*/
|
||||||
public class Aggregation {
|
public class Aggregation {
|
||||||
|
|
||||||
public static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
|
/**
|
||||||
|
* References the root document, i.e. the top-level document, currently being processed in the aggregation pipeline
|
||||||
|
* stage.
|
||||||
|
*/
|
||||||
|
public static final String ROOT = SystemVariable.ROOT.toString();
|
||||||
|
|
||||||
private final List<AggregationOperation> operations;
|
/**
|
||||||
|
* References the start of the field path being processed in the aggregation pipeline stage. Unless documented
|
||||||
|
* otherwise, all stages start with CURRENT the same as ROOT.
|
||||||
|
*/
|
||||||
|
public static final String CURRENT = SystemVariable.CURRENT.toString();
|
||||||
|
|
||||||
|
public static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
|
||||||
|
public static final AggregationOptions DEFAULT_OPTIONS = newAggregationOptions().build();
|
||||||
|
|
||||||
|
protected final List<AggregationOperation> operations;
|
||||||
|
private final AggregationOptions options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||||
@@ -66,6 +81,20 @@ public class Aggregation {
|
|||||||
return new Aggregation(operations);
|
return new Aggregation(operations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this {@link Aggregation} with the given {@link AggregationOptions} set. Note that options are
|
||||||
|
* supported in MongoDB version 2.6+.
|
||||||
|
*
|
||||||
|
* @param options must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public Aggregation withOptions(AggregationOptions options) {
|
||||||
|
|
||||||
|
Assert.notNull(options, "AggregationOptions must not be null.");
|
||||||
|
return new Aggregation(this.operations, options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
|
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
|
||||||
*
|
*
|
||||||
@@ -92,11 +121,43 @@ public class Aggregation {
|
|||||||
* @param aggregationOperations must not be {@literal null} or empty.
|
* @param aggregationOperations must not be {@literal null} or empty.
|
||||||
*/
|
*/
|
||||||
protected Aggregation(AggregationOperation... aggregationOperations) {
|
protected Aggregation(AggregationOperation... aggregationOperations) {
|
||||||
|
this(asAggregationList(aggregationOperations));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aggregationOperations must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected static List<AggregationOperation> asAggregationList(AggregationOperation... aggregationOperations) {
|
||||||
|
|
||||||
|
Assert.notEmpty(aggregationOperations, "AggregationOperations must not be null or empty!");
|
||||||
|
|
||||||
|
return Arrays.asList(aggregationOperations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @param aggregationOperations must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
protected Aggregation(List<AggregationOperation> aggregationOperations) {
|
||||||
|
this(aggregationOperations, DEFAULT_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @param aggregationOperations must not be {@literal null} or empty.
|
||||||
|
* @param options must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
protected Aggregation(List<AggregationOperation> aggregationOperations, AggregationOptions options) {
|
||||||
|
|
||||||
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
|
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
|
||||||
Assert.isTrue(aggregationOperations.length > 0, "At least one AggregationOperation has to be provided");
|
Assert.isTrue(aggregationOperations.size() > 0, "At least one AggregationOperation has to be provided");
|
||||||
|
Assert.notNull(options, "AggregationOptions must not be null!");
|
||||||
|
|
||||||
this.operations = Arrays.asList(aggregationOperations);
|
this.operations = aggregationOperations;
|
||||||
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,6 +292,29 @@ public class Aggregation {
|
|||||||
return Fields.from(field(name, target));
|
return Fields.from(field(name, target));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the{@code distanceField}. The
|
||||||
|
* {@code distanceField} defines output field that contains the calculated distance.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param distanceField must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public static GeoNearOperation geoNear(NearQuery query, String distanceField) {
|
||||||
|
return new GeoNearOperation(query, distanceField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link AggregationOptions.Builder}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public static AggregationOptions.Builder newAggregationOptions() {
|
||||||
|
return new AggregationOptions.Builder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts this {@link Aggregation} specification to a {@link DBObject}.
|
* Converts this {@link Aggregation} specification to a {@link DBObject}.
|
||||||
*
|
*
|
||||||
@@ -248,13 +332,15 @@ public class Aggregation {
|
|||||||
|
|
||||||
if (operation instanceof FieldsExposingAggregationOperation) {
|
if (operation instanceof FieldsExposingAggregationOperation) {
|
||||||
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
|
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
|
||||||
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields());
|
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), rootContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject command = new BasicDBObject("aggregate", inputCollectionName);
|
DBObject command = new BasicDBObject("aggregate", inputCollectionName);
|
||||||
command.put("pipeline", operationDocuments);
|
command.put("pipeline", operationDocuments);
|
||||||
|
|
||||||
|
command = options.applyAndReturnPotentiallyChangedCommand(command);
|
||||||
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,4 +388,51 @@ public class Aggregation {
|
|||||||
return new FieldReference(new ExposedField(new AggregationField(name), true));
|
return new FieldReference(new ExposedField(new AggregationField(name), true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the system variables available in MongoDB aggregation framework pipeline expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/aggregation-variables
|
||||||
|
*/
|
||||||
|
enum SystemVariable {
|
||||||
|
|
||||||
|
ROOT, CURRENT;
|
||||||
|
|
||||||
|
private static final String PREFIX = "$$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return {@literal true} if the given {@code fieldRef} denotes a well-known system variable, {@literal false}
|
||||||
|
* otherwise.
|
||||||
|
*
|
||||||
|
* @param fieldRef may be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isReferingToSystemVariable(String fieldRef) {
|
||||||
|
|
||||||
|
if (fieldRef == null || !fieldRef.startsWith(PREFIX) || fieldRef.length() <= 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indexOfFirstDot = fieldRef.indexOf('.');
|
||||||
|
String candidate = fieldRef.substring(2, indexOfFirstDot == -1 ? fieldRef.length() : indexOfFirstDot);
|
||||||
|
|
||||||
|
for (SystemVariable value : values()) {
|
||||||
|
if (value.name().equals(candidate)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Enum#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return PREFIX.concat(name());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.aggregation;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds a set of configurable aggregation options that can be used within an aggregation pipeline. A list of support
|
||||||
|
* aggregation options can be found in the MongoDB reference documentation
|
||||||
|
* http://docs.mongodb.org/manual/reference/command/aggregate/#aggregate
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @see Aggregation#withOptions(AggregationOptions)
|
||||||
|
* @see TypedAggregation#withOptions(AggregationOptions)
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public class AggregationOptions {
|
||||||
|
|
||||||
|
private static final String CURSOR = "cursor";
|
||||||
|
private static final String EXPLAIN = "explain";
|
||||||
|
private static final String ALLOW_DISK_USE = "allowDiskUse";
|
||||||
|
|
||||||
|
private final boolean allowDiskUse;
|
||||||
|
private final boolean explain;
|
||||||
|
private final DBObject cursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link AggregationOptions}.
|
||||||
|
*
|
||||||
|
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
|
||||||
|
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
|
||||||
|
* @param cursor can be {@literal null}, used to pass additional options to the aggregation.
|
||||||
|
*/
|
||||||
|
public AggregationOptions(boolean allowDiskUse, boolean explain, DBObject cursor) {
|
||||||
|
|
||||||
|
this.allowDiskUse = allowDiskUse;
|
||||||
|
this.explain = explain;
|
||||||
|
this.cursor = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables writing to temporary files. When set to true, aggregation stages can write data to the _tmp subdirectory in
|
||||||
|
* the dbPath directory.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isAllowDiskUse() {
|
||||||
|
return allowDiskUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies to return the information on the processing of the pipeline.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isExplain() {
|
||||||
|
return explain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a document that contains options that control the creation of the cursor object.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DBObject getCursor() {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new potentially adjusted copy for the given {@code aggregationCommandObject} with the configuration
|
||||||
|
* applied.
|
||||||
|
*
|
||||||
|
* @param command the aggregation command.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
DBObject applyAndReturnPotentiallyChangedCommand(DBObject command) {
|
||||||
|
|
||||||
|
DBObject result = new BasicDBObject(command.toMap());
|
||||||
|
|
||||||
|
if (allowDiskUse && !result.containsField(ALLOW_DISK_USE)) {
|
||||||
|
result.put(ALLOW_DISK_USE, allowDiskUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explain && !result.containsField(EXPLAIN)) {
|
||||||
|
result.put(EXPLAIN, explain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null && !result.containsField(CURSOR)) {
|
||||||
|
result.put("cursor", cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link DBObject} representation of this {@link AggregationOptions}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DBObject toDbObject() {
|
||||||
|
|
||||||
|
DBObject dbo = new BasicDBObject();
|
||||||
|
dbo.put(ALLOW_DISK_USE, allowDiskUse);
|
||||||
|
dbo.put(EXPLAIN, explain);
|
||||||
|
dbo.put(CURSOR, cursor);
|
||||||
|
|
||||||
|
return dbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toDbObject().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Builder for {@link AggregationOptions}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private boolean allowDiskUse;
|
||||||
|
private boolean explain;
|
||||||
|
private DBObject cursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines whether to off-load intensive sort-operations to disk.
|
||||||
|
*
|
||||||
|
* @param allowDiskUse
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder allowDiskUse(boolean allowDiskUse) {
|
||||||
|
|
||||||
|
this.allowDiskUse = allowDiskUse;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines whether to get the execution plan for the aggregation instead of the actual results.
|
||||||
|
*
|
||||||
|
* @param explain
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder explain(boolean explain) {
|
||||||
|
|
||||||
|
this.explain = explain;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional options to the aggregation.
|
||||||
|
*
|
||||||
|
* @param cursor
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder cursor(DBObject cursor) {
|
||||||
|
|
||||||
|
this.cursor = cursor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link AggregationOptions} instance with the given configuration.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AggregationOptions build() {
|
||||||
|
return new AggregationOptions(allowDiskUse, explain, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2014 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.
|
||||||
@@ -28,6 +28,7 @@ import com.mongodb.DBObject;
|
|||||||
*
|
*
|
||||||
* @author Tobias Trelle
|
* @author Tobias Trelle
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
* @param <T> The class in which the results are mapped onto.
|
* @param <T> The class in which the results are mapped onto.
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
@@ -90,6 +91,16 @@ public class AggregationResults<T> implements Iterable<T> {
|
|||||||
return serverUsed;
|
return serverUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw result that was returned by the server.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public DBObject getRawResults() {
|
||||||
|
return rawResults;
|
||||||
|
}
|
||||||
|
|
||||||
private String parseServerUsed() {
|
private String parseServerUsed() {
|
||||||
|
|
||||||
Object object = rawResults.get("serverUsed");
|
Object object = rawResults.get("serverUsed");
|
||||||
|
|||||||
@@ -268,14 +268,21 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
|||||||
return field.isAliased();
|
return field.isAliased();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the synthetic
|
||||||
|
*/
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return synthetic;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the field can be referred to using the given name.
|
* Returns whether the field can be referred to using the given name.
|
||||||
*
|
*
|
||||||
* @param input
|
* @param name
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean canBeReferredToBy(String input) {
|
public boolean canBeReferredToBy(String name) {
|
||||||
return getTarget().equals(input);
|
return getName().equals(name) || getTarget().equals(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,6 +347,7 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
|||||||
public FieldReference(ExposedField field) {
|
public FieldReference(ExposedField field) {
|
||||||
|
|
||||||
Assert.notNull(field, "ExposedField must not be null!");
|
Assert.notNull(field, "ExposedField must not be null!");
|
||||||
|
|
||||||
this.field = field;
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2014 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,16 +32,22 @@ import com.mongodb.DBObject;
|
|||||||
class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
|
class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
|
||||||
|
|
||||||
private final ExposedFields exposedFields;
|
private final ExposedFields exposedFields;
|
||||||
|
private final AggregationOperationContext rootContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}.
|
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
|
||||||
|
* {@link AggregationOperationContext} to perform a mapping to mongo types if necessary.
|
||||||
*
|
*
|
||||||
* @param exposedFields must not be {@literal null}.
|
* @param exposedFields must not be {@literal null}.
|
||||||
|
* @param rootContext must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields) {
|
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields, AggregationOperationContext rootContext) {
|
||||||
|
|
||||||
Assert.notNull(exposedFields, "ExposedFields must not be null!");
|
Assert.notNull(exposedFields, "ExposedFields must not be null!");
|
||||||
|
Assert.notNull(rootContext, "RootContext must not be null!");
|
||||||
|
|
||||||
this.exposedFields = exposedFields;
|
this.exposedFields = exposedFields;
|
||||||
|
this.rootContext = rootContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -50,7 +56,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DBObject getMappedObject(DBObject dbObject) {
|
public DBObject getMappedObject(DBObject dbObject) {
|
||||||
return dbObject;
|
return rootContext.getMappedObject(dbObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -59,7 +65,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(Field field) {
|
public FieldReference getReference(Field field) {
|
||||||
return getReference(field.getTarget());
|
return getReference(field, field.getTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -68,11 +74,42 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(String name) {
|
public FieldReference getReference(String name) {
|
||||||
|
return getReference(null, name);
|
||||||
|
}
|
||||||
|
|
||||||
ExposedField field = exposedFields.getField(name);
|
/**
|
||||||
|
* Returns a {@link FieldReference} to the given {@link Field} with the given {@code name}.
|
||||||
|
*
|
||||||
|
* @param field may be {@literal null}
|
||||||
|
* @param name must not be {@literal null}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private FieldReference getReference(Field field, String name) {
|
||||||
|
|
||||||
|
Assert.notNull(name, "Name must not be null!");
|
||||||
|
|
||||||
|
ExposedField exposedField = exposedFields.getField(name);
|
||||||
|
|
||||||
|
if (exposedField != null) {
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
return new FieldReference(field);
|
// we return a FieldReference to the given field directly to make sure that we reference the proper alias here.
|
||||||
|
return new FieldReference(new ExposedField(field, exposedField.isSynthetic()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FieldReference(exposedField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.contains(".")) {
|
||||||
|
|
||||||
|
// for nested field references we only check that the root field exists.
|
||||||
|
ExposedField rootField = exposedFields.getField(name.split("\\.")[0]);
|
||||||
|
|
||||||
|
if (rootField != null) {
|
||||||
|
|
||||||
|
// We have to synthetic to true, in order to render the field-name as is.
|
||||||
|
return new FieldReference(new ExposedField(name, true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
|
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2014 the original author or authors.
|
* Copyright 2013-2015 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.
|
||||||
@@ -30,6 +30,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* Value object to capture a list of {@link Field} instances.
|
* Value object to capture a list of {@link Field} instances.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public final class Fields implements Iterable<Field> {
|
public final class Fields implements Iterable<Field> {
|
||||||
@@ -83,6 +84,15 @@ public final class Fields implements Iterable<Field> {
|
|||||||
return new AggregationField(name);
|
return new AggregationField(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link Field} with the given {@code name} and {@code target}.
|
||||||
|
* <p>
|
||||||
|
* The {@code target} is the name of the backing document field that will be aliased with {@code name}.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param target must not be {@literal null} or empty
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static Field field(String name, String target) {
|
public static Field field(String name, String target) {
|
||||||
Assert.hasText(target, "Target must not be null or empty!");
|
Assert.hasText(target, "Target must not be null or empty!");
|
||||||
return new AggregationField(name, target);
|
return new AggregationField(name, target);
|
||||||
@@ -186,15 +196,24 @@ public final class Fields implements Iterable<Field> {
|
|||||||
private final String target;
|
private final String target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an aggregation fieldwith the given name. As no target is set explicitly, the name will be used as target
|
* Creates an aggregation field with the given {@code name}.
|
||||||
* as well.
|
|
||||||
*
|
*
|
||||||
* @param key
|
* @see AggregationField#AggregationField(String, String).
|
||||||
|
* @param name must not be {@literal null} or empty
|
||||||
*/
|
*/
|
||||||
public AggregationField(String key) {
|
public AggregationField(String name) {
|
||||||
this(key, null);
|
this(name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an aggregation field with the given {@code name} and {@code target}.
|
||||||
|
* <p>
|
||||||
|
* The {@code name} serves as an alias for the actual backing document field denoted by {@code target}. If no target
|
||||||
|
* is set explicitly, the name will be used as target.
|
||||||
|
*
|
||||||
|
* @param name must not be {@literal null} or empty
|
||||||
|
* @param target
|
||||||
|
*/
|
||||||
public AggregationField(String name, String target) {
|
public AggregationField(String name, String target) {
|
||||||
|
|
||||||
String nameToSet = cleanUp(name);
|
String nameToSet = cleanUp(name);
|
||||||
@@ -217,6 +236,10 @@ public final class Fields implements Iterable<Field> {
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Aggregation.SystemVariable.isReferingToSystemVariable(source)) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
int dollarIndex = source.lastIndexOf('$');
|
int dollarIndex = source.lastIndexOf('$');
|
||||||
return dollarIndex == -1 ? source : source.substring(dollarIndex + 1);
|
return dollarIndex == -1 ? source : source.substring(dollarIndex + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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,17 +22,33 @@ import com.mongodb.BasicDBObject;
|
|||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Represents a {@code geoNear} aggregation operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#geoNear(NearQuery, String)} instead of creating
|
||||||
|
* instances of this class directly.
|
||||||
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class GeoNearOperation implements AggregationOperation {
|
public class GeoNearOperation implements AggregationOperation {
|
||||||
|
|
||||||
private final NearQuery nearQuery;
|
private final NearQuery nearQuery;
|
||||||
|
private final String distanceField;
|
||||||
|
|
||||||
public GeoNearOperation(NearQuery nearQuery) {
|
/**
|
||||||
|
* Creates a new {@link GeoNearOperation} from the given {@link NearQuery} and the given distance field. The
|
||||||
|
* {@code distanceField} defines output field that contains the calculated distance.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param distanceField must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoNearOperation(NearQuery nearQuery, String distanceField) {
|
||||||
|
|
||||||
|
Assert.notNull(nearQuery, "NearQuery must not be null.");
|
||||||
|
Assert.hasLength(distanceField, "Distance field must not be null or empty.");
|
||||||
|
|
||||||
Assert.notNull(nearQuery);
|
|
||||||
this.nearQuery = nearQuery;
|
this.nearQuery = nearQuery;
|
||||||
|
this.distanceField = distanceField;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -41,6 +57,10 @@ public class GeoNearOperation implements AggregationOperation {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DBObject toDBObject(AggregationOperationContext context) {
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
return new BasicDBObject("$geoNear", context.getMappedObject(nearQuery.toDBObject()));
|
|
||||||
|
BasicDBObject command = (BasicDBObject) context.getMappedObject(nearQuery.toDBObject());
|
||||||
|
command.put("distanceField", distanceField);
|
||||||
|
|
||||||
|
return new BasicDBObject("$geoNear", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2014 the original author or authors.
|
* Copyright 2013-2015 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,6 +31,9 @@ import com.mongodb.DBObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the aggregation framework {@code $group}-operation.
|
* Encapsulates the aggregation framework {@code $group}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#group(Fields)} instead of creating instances of this
|
||||||
|
* class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/group/#stage._S_group
|
* @see http://docs.mongodb.org/manual/reference/aggregation/group/#stage._S_group
|
||||||
* @author Sebastian Herold
|
* @author Sebastian Herold
|
||||||
@@ -364,7 +367,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object getValue(AggregationOperationContext context) {
|
public Object getValue(AggregationOperationContext context) {
|
||||||
return reference == null ? value : context.getReference(reference).toString();
|
|
||||||
|
if (reference == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Aggregation.SystemVariable.isReferingToSystemVariable(reference)) {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getReference(reference).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,14 +21,17 @@ import com.mongodb.BasicDBObject;
|
|||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the {@code $limit}-operation
|
* Encapsulates the {@code $limit}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#limit(long)} instead of creating instances of this
|
||||||
|
* class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/limit/
|
* @see http://docs.mongodb.org/manual/reference/aggregation/limit/
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
class LimitOperation implements AggregationOperation {
|
public class LimitOperation implements AggregationOperation {
|
||||||
|
|
||||||
private final long maxElements;
|
private final long maxElements;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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,14 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.aggregation;
|
package org.springframework.data.mongodb.core.aggregation;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the {@code $match}-operation
|
* Encapsulates the {@code $match}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method
|
||||||
|
* {@link Aggregation#match(org.springframework.data.mongodb.core.query.Criteria)} instead of creating instances of this
|
||||||
|
* class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/match/
|
* @see http://docs.mongodb.org/manual/reference/aggregation/match/
|
||||||
* @author Sebastian Herold
|
* @author Sebastian Herold
|
||||||
@@ -32,17 +36,17 @@ import com.mongodb.DBObject;
|
|||||||
*/
|
*/
|
||||||
public class MatchOperation implements AggregationOperation {
|
public class MatchOperation implements AggregationOperation {
|
||||||
|
|
||||||
private final Criteria criteria;
|
private final CriteriaDefinition criteriaDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link MatchOperation} for the given {@link Criteria}.
|
* Creates a new {@link MatchOperation} for the given {@link CriteriaDefinition}.
|
||||||
*
|
*
|
||||||
* @param criteria must not be {@literal null}.
|
* @param criteriaDefinition must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public MatchOperation(Criteria criteria) {
|
public MatchOperation(CriteriaDefinition criteriaDefinition) {
|
||||||
|
|
||||||
Assert.notNull(criteria, "Criteria must not be null!");
|
Assert.notNull(criteriaDefinition, "Criteria must not be null!");
|
||||||
this.criteria = criteria;
|
this.criteriaDefinition = criteriaDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -51,6 +55,6 @@ public class MatchOperation implements AggregationOperation {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DBObject toDBObject(AggregationOperationContext context) {
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
return new BasicDBObject("$match", context.getMappedObject(criteria.getCriteriaObject()));
|
return new BasicDBObject("$match", context.getMappedObject(criteriaDefinition.getCriteriaObject()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2014 the original author or authors.
|
* Copyright 2013-2015 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,15 +24,17 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedFi
|
|||||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
|
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the aggregation framework {@code $project}-operation. Projection of field to be used in an
|
* Encapsulates the aggregation framework {@code $project}-operation.
|
||||||
* {@link Aggregation}. A projection is similar to a {@link Field} inclusion/exclusion but more powerful. It can
|
|
||||||
* generate new fields, change values of given field etc.
|
|
||||||
* <p>
|
* <p>
|
||||||
|
* Projection of field to be used in an {@link Aggregation}. A projection is similar to a {@link Field}
|
||||||
|
* inclusion/exclusion but more powerful. It can generate new fields, change values of given field etc.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#project(Fields)} instead of creating instances of
|
||||||
|
* this class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/project/
|
* @see http://docs.mongodb.org/manual/reference/aggregation/project/
|
||||||
* @author Tobias Trelle
|
* @author Tobias Trelle
|
||||||
@@ -235,26 +237,53 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* An {@link ProjectionOperationBuilder} that is used for SpEL expression based projections.
|
||||||
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public static class ExpressionProjectionOperationBuilder extends AbstractProjectionOperationBuilder {
|
public static class ExpressionProjectionOperationBuilder extends ProjectionOperationBuilder {
|
||||||
|
|
||||||
private final Object[] params;
|
private final Object[] params;
|
||||||
|
private final String expression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ExpressionProjectionOperationBuilder} for the given value, {@link ProjectionOperation} and
|
* Creates a new {@link ExpressionProjectionOperationBuilder} for the given value, {@link ProjectionOperation} and
|
||||||
* parameters.
|
* parameters.
|
||||||
*
|
*
|
||||||
* @param value must not be {@literal null}.
|
* @param expression must not be {@literal null}.
|
||||||
* @param operation must not be {@literal null}.
|
* @param operation must not be {@literal null}.
|
||||||
* @param parameters
|
* @param parameters
|
||||||
*/
|
*/
|
||||||
public ExpressionProjectionOperationBuilder(Object value, ProjectionOperation operation, Object[] parameters) {
|
public ExpressionProjectionOperationBuilder(String expression, ProjectionOperation operation, Object[] parameters) {
|
||||||
|
|
||||||
super(value, operation);
|
super(expression, operation, null);
|
||||||
|
this.expression = expression;
|
||||||
this.params = parameters.clone();
|
this.params = parameters.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder#project(java.lang.String, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ProjectionOperationBuilder project(String operation, final Object... values) {
|
||||||
|
|
||||||
|
OperationProjection operationProjection = new OperationProjection(Fields.field(value.toString()), operation,
|
||||||
|
values) {
|
||||||
|
@Override
|
||||||
|
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||||
|
|
||||||
|
List<Object> result = new ArrayList<Object>(values.length + 1);
|
||||||
|
result.add(ExpressionProjection.toMongoExpression(context,
|
||||||
|
ExpressionProjectionOperationBuilder.this.expression, ExpressionProjectionOperationBuilder.this.params));
|
||||||
|
result.addAll(Arrays.asList(values));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ProjectionOperationBuilder(value, this.operation.and(operationProjection), operationProjection);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#as(java.lang.String)
|
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#as(java.lang.String)
|
||||||
@@ -303,7 +332,11 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DBObject toDBObject(AggregationOperationContext context) {
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
return new BasicDBObject(getExposedField().getName(), TRANSFORMER.transform(expression, context, params));
|
return new BasicDBObject(getExposedField().getName(), toMongoExpression(context, expression, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Object toMongoExpression(AggregationOperationContext context, String expression, Object[] params) {
|
||||||
|
return TRANSFORMER.transform(expression, context, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +353,6 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
private static final String FIELD_REFERENCE_NOT_NULL = "Field reference must not be null!";
|
private static final String FIELD_REFERENCE_NOT_NULL = "Field reference must not be null!";
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final ProjectionOperation operation;
|
|
||||||
private final OperationProjection previousProjection;
|
private final OperationProjection previousProjection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,7 +367,23 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
super(name, operation);
|
super(name, operation);
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.operation = operation;
|
this.previousProjection = previousProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ProjectionOperationBuilder} for the field with the given value on top of the given
|
||||||
|
* {@link ProjectionOperation}.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @param operation
|
||||||
|
* @param previousProjection
|
||||||
|
*/
|
||||||
|
protected ProjectionOperationBuilder(Object value, ProjectionOperation operation,
|
||||||
|
OperationProjection previousProjection) {
|
||||||
|
|
||||||
|
super(value, operation);
|
||||||
|
|
||||||
|
this.name = null;
|
||||||
this.previousProjection = previousProjection;
|
this.previousProjection = previousProjection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,8 +569,9 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder project(String operation, Object... values) {
|
public ProjectionOperationBuilder project(String operation, Object... values) {
|
||||||
OperationProjection projectionOperation = new OperationProjection(Fields.field(name), operation, values);
|
OperationProjection operationProjection = new OperationProjection(Fields.field(value.toString()), operation,
|
||||||
return new ProjectionOperationBuilder(name, this.operation.and(projectionOperation), projectionOperation);
|
values);
|
||||||
|
return new ProjectionOperationBuilder(value, this.operation.and(operationProjection), operationProjection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -627,6 +676,10 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
// implicit reference or explicit include?
|
// implicit reference or explicit include?
|
||||||
if (value == null || Boolean.TRUE.equals(value)) {
|
if (value == null || Boolean.TRUE.equals(value)) {
|
||||||
|
|
||||||
|
if (Aggregation.SystemVariable.isReferingToSystemVariable(field.getTarget())) {
|
||||||
|
return field.getTarget();
|
||||||
|
}
|
||||||
|
|
||||||
// check whether referenced field exists in the context
|
// check whether referenced field exists in the context
|
||||||
return context.getReference(field).getReferenceValue();
|
return context.getReference(field).getReferenceValue();
|
||||||
|
|
||||||
@@ -649,7 +702,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
/**
|
/**
|
||||||
* Creates a new {@link OperationProjection} for the given field.
|
* Creates a new {@link OperationProjection} for the given field.
|
||||||
*
|
*
|
||||||
* @param name the name of the field to add the operation projection for, must not be {@literal null} or empty.
|
* @param field the name of the field to add the operation projection for, must not be {@literal null} or empty.
|
||||||
* @param operation the actual operation key, must not be {@literal null} or empty.
|
* @param operation the actual operation key, must not be {@literal null} or empty.
|
||||||
* @param values the values to pass into the operation, must not be {@literal null}.
|
* @param values the values to pass into the operation, must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
@@ -672,18 +725,15 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
@Override
|
@Override
|
||||||
public DBObject toDBObject(AggregationOperationContext context) {
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
|
|
||||||
BasicDBList values = new BasicDBList();
|
DBObject inner = new BasicDBObject("$" + operation, getOperationArguments(context));
|
||||||
values.addAll(buildReferences(context));
|
|
||||||
|
|
||||||
DBObject inner = new BasicDBObject("$" + operation, values);
|
return new BasicDBObject(getField().getName(), inner);
|
||||||
|
|
||||||
return new BasicDBObject(this.field.getName(), inner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Object> buildReferences(AggregationOperationContext context) {
|
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||||
|
|
||||||
List<Object> result = new ArrayList<Object>(values.size());
|
List<Object> result = new ArrayList<Object>(values.size());
|
||||||
result.add(context.getReference(field.getTarget()).toString());
|
result.add(context.getReference(getField().getName()).toString());
|
||||||
|
|
||||||
for (Object element : values) {
|
for (Object element : values) {
|
||||||
result.add(element instanceof Field ? context.getReference((Field) element).toString() : element);
|
result.add(element instanceof Field ? context.getReference((Field) element).toString() : element);
|
||||||
@@ -692,6 +742,15 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the field that holds the {@link OperationProjection}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Field getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of this {@link OperationProjection} with the given alias.
|
* Creates a new instance of this {@link OperationProjection} with the given alias.
|
||||||
*
|
*
|
||||||
@@ -699,7 +758,27 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public OperationProjection withAlias(String alias) {
|
public OperationProjection withAlias(String alias) {
|
||||||
return new OperationProjection(Fields.field(alias, this.field.getName()), operation, values.toArray());
|
|
||||||
|
final Field aliasedField = Fields.field(alias, this.field.getName());
|
||||||
|
return new OperationProjection(aliasedField, operation, values.toArray()) {
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.OperationProjection#getField()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Field getField() {
|
||||||
|
return aliasedField;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||||
|
|
||||||
|
// We have to make sure that we use the arguments from the "previous" OperationProjection that we replace
|
||||||
|
// with this new instance.
|
||||||
|
|
||||||
|
return OperationProjection.this.getOperationArguments(context);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,6 +810,96 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
return new BasicDBObject(name, nestedObject);
|
return new BasicDBObject(name, nestedObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the minute from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractMinute() {
|
||||||
|
return project("minute");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the hour from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractHour() {
|
||||||
|
return project("hour");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the second from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractSecond() {
|
||||||
|
return project("second");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the millisecond from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractMillisecond() {
|
||||||
|
return project("millisecond");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the year from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractYear() {
|
||||||
|
return project("year");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the month from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractMonth() {
|
||||||
|
return project("month");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the week from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractWeek() {
|
||||||
|
return project("week");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the dayOfYear from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractDayOfYear() {
|
||||||
|
return project("dayOfYear");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the dayOfMonth from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractDayOfMonth() {
|
||||||
|
return project("dayOfMonth");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the dayOfWeek from a date expression.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder extractDayOfWeek() {
|
||||||
|
return project("dayOfWeek");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -771,5 +940,4 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
|||||||
*/
|
*/
|
||||||
public abstract DBObject toDBObject(AggregationOperationContext context);
|
public abstract DBObject toDBObject(AggregationOperationContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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,6 +22,9 @@ import com.mongodb.DBObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the aggregation framework {@code $skip}-operation.
|
* Encapsulates the aggregation framework {@code $skip}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#skip(int)} instead of creating instances of this
|
||||||
|
* class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/skip/
|
* @see http://docs.mongodb.org/manual/reference/aggregation/skip/
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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,9 @@ import com.mongodb.DBObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the aggregation framework {@code $sort}-operation.
|
* Encapsulates the aggregation framework {@code $sort}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#sort(Direction, String...)} instead of creating
|
||||||
|
* instances of this class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/sort/#pipe._S_sort
|
* @see http://docs.mongodb.org/manual/reference/aggregation/sort/#pipe._S_sort
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2014 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.aggregation;
|
package org.springframework.data.mongodb.core.aggregation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,11 +32,34 @@ public class TypedAggregation<I> extends Aggregation {
|
|||||||
/**
|
/**
|
||||||
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s.
|
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s.
|
||||||
*
|
*
|
||||||
|
* @param inputType must not be {@literal null}.
|
||||||
* @param operations must not be {@literal null} or empty.
|
* @param operations must not be {@literal null} or empty.
|
||||||
*/
|
*/
|
||||||
public TypedAggregation(Class<I> inputType, AggregationOperation... operations) {
|
public TypedAggregation(Class<I> inputType, AggregationOperation... operations) {
|
||||||
|
this(inputType, asAggregationList(operations));
|
||||||
|
}
|
||||||
|
|
||||||
super(operations);
|
/**
|
||||||
|
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @param inputType must not be {@literal null}.
|
||||||
|
* @param operations must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
public TypedAggregation(Class<I> inputType, List<AggregationOperation> operations) {
|
||||||
|
this(inputType, operations, DEFAULT_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s and the given
|
||||||
|
* {@link AggregationOptions}.
|
||||||
|
*
|
||||||
|
* @param inputType must not be {@literal null}.
|
||||||
|
* @param operations must not be {@literal null} or empty.
|
||||||
|
* @param options must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public TypedAggregation(Class<I> inputType, List<AggregationOperation> operations, AggregationOptions options) {
|
||||||
|
|
||||||
|
super(operations, options);
|
||||||
|
|
||||||
Assert.notNull(inputType, "Input type must not be null!");
|
Assert.notNull(inputType, "Input type must not be null!");
|
||||||
this.inputType = inputType;
|
this.inputType = inputType;
|
||||||
@@ -48,4 +73,14 @@ public class TypedAggregation<I> extends Aggregation {
|
|||||||
public Class<I> getInputType() {
|
public Class<I> getInputType() {
|
||||||
return inputType;
|
return inputType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.Aggregation#withOptions(org.springframework.data.mongodb.core.aggregation.AggregationOptions)
|
||||||
|
*/
|
||||||
|
public TypedAggregation<I> withOptions(AggregationOptions options) {
|
||||||
|
|
||||||
|
Assert.notNull(options, "AggregationOptions must not be null.");
|
||||||
|
return new TypedAggregation<I>(inputType, operations, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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.
|
||||||
@@ -23,6 +23,9 @@ import com.mongodb.DBObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the aggregation framework {@code $unwind}-operation.
|
* Encapsulates the aggregation framework {@code $unwind}-operation.
|
||||||
|
* <p>
|
||||||
|
* We recommend to use the static factory method {@link Aggregation#unwind(String)} instead of creating instances of
|
||||||
|
* this class directly.
|
||||||
*
|
*
|
||||||
* @see http://docs.mongodb.org/manual/reference/aggregation/unwind/#pipe._S_unwind
|
* @see http://docs.mongodb.org/manual/reference/aggregation/unwind/#pipe._S_unwind
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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,14 +17,15 @@ package org.springframework.data.mongodb.core.convert;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -36,17 +37,23 @@ import org.springframework.core.convert.converter.GenericConverter;
|
|||||||
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
import org.springframework.data.convert.JodaTimeConverters;
|
import org.springframework.data.convert.JodaTimeConverters;
|
||||||
|
import org.springframework.data.convert.Jsr310Converters;
|
||||||
import org.springframework.data.convert.ReadingConverter;
|
import org.springframework.data.convert.ReadingConverter;
|
||||||
|
import org.springframework.data.convert.ThreeTenBackPortConverters;
|
||||||
import org.springframework.data.convert.WritingConverter;
|
import org.springframework.data.convert.WritingConverter;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
|
||||||
|
import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter;
|
||||||
|
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter;
|
||||||
|
import org.springframework.data.mongodb.core.convert.MongoConverters.TermToStringConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||||
|
import org.springframework.data.util.CacheValue;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +65,7 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class CustomConversions {
|
public class CustomConversions {
|
||||||
|
|
||||||
@@ -69,10 +77,13 @@ public class CustomConversions {
|
|||||||
private final Set<ConvertiblePair> writingPairs;
|
private final Set<ConvertiblePair> writingPairs;
|
||||||
private final Set<Class<?>> customSimpleTypes;
|
private final Set<Class<?>> customSimpleTypes;
|
||||||
private final SimpleTypeHolder simpleTypeHolder;
|
private final SimpleTypeHolder simpleTypeHolder;
|
||||||
private final ConcurrentMap<ConvertiblePair, CacheValue> customReadTargetTypes;
|
|
||||||
|
|
||||||
private final List<Object> converters;
|
private final List<Object> converters;
|
||||||
|
|
||||||
|
private final Map<ConvertiblePair, CacheValue<Class<?>>> customReadTargetTypes;
|
||||||
|
private final Map<ConvertiblePair, CacheValue<Class<?>>> customWriteTargetTypes;
|
||||||
|
private final Map<Class<?>, CacheValue<Class<?>>> rawWriteTargetTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty {@link CustomConversions} object.
|
* Creates an empty {@link CustomConversions} object.
|
||||||
*/
|
*/
|
||||||
@@ -92,7 +103,9 @@ public class CustomConversions {
|
|||||||
this.readingPairs = new LinkedHashSet<ConvertiblePair>();
|
this.readingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||||
this.writingPairs = new LinkedHashSet<ConvertiblePair>();
|
this.writingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||||
this.customSimpleTypes = new HashSet<Class<?>>();
|
this.customSimpleTypes = new HashSet<Class<?>>();
|
||||||
this.customReadTargetTypes = new ConcurrentHashMap<GenericConverter.ConvertiblePair, CacheValue>();
|
this.customReadTargetTypes = new ConcurrentHashMap<ConvertiblePair, CacheValue<Class<?>>>();
|
||||||
|
this.customWriteTargetTypes = new ConcurrentHashMap<ConvertiblePair, CacheValue<Class<?>>>();
|
||||||
|
this.rawWriteTargetTypes = new ConcurrentHashMap<Class<?>, CacheValue<Class<?>>>();
|
||||||
|
|
||||||
List<Object> toRegister = new ArrayList<Object>();
|
List<Object> toRegister = new ArrayList<Object>();
|
||||||
|
|
||||||
@@ -106,9 +119,14 @@ public class CustomConversions {
|
|||||||
toRegister.add(URLToStringConverter.INSTANCE);
|
toRegister.add(URLToStringConverter.INSTANCE);
|
||||||
toRegister.add(StringToURLConverter.INSTANCE);
|
toRegister.add(StringToURLConverter.INSTANCE);
|
||||||
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(TermToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(NamedMongoScriptToDBObjectConverter.INSTANCE);
|
||||||
|
toRegister.add(DBObjectToNamedMongoScriptCoverter.INSTANCE);
|
||||||
|
|
||||||
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
||||||
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
||||||
|
toRegister.addAll(Jsr310Converters.getConvertersToRegister());
|
||||||
|
toRegister.addAll(ThreeTenBackPortConverters.getConvertersToRegister());
|
||||||
|
|
||||||
for (Object c : toRegister) {
|
for (Object c : toRegister) {
|
||||||
registerConversion(c);
|
registerConversion(c);
|
||||||
@@ -235,70 +253,103 @@ public class CustomConversions {
|
|||||||
* @param sourceType must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Class<?> getCustomWriteTarget(Class<?> sourceType) {
|
public Class<?> getCustomWriteTarget(final Class<?> sourceType) {
|
||||||
return getCustomWriteTarget(sourceType, null);
|
|
||||||
|
return getOrCreateAndCache(sourceType, rawWriteTargetTypes, new Producer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> get() {
|
||||||
|
return getCustomTarget(sourceType, null, writingPairs);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the target type we can write an onject of the given source type to. The returned type might be a subclass
|
* Returns the target type we can readTargetWriteLocl an inject of the given source type to. The returned type might
|
||||||
* oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the
|
* be a subclass of the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply
|
||||||
* first target type matching or {@literal null} if no conversion can be found.
|
* return the first target type matching or {@literal null} if no conversion can be found.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @param requestedTargetType
|
* @param requestedTargetType
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Class<?> getCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
public Class<?> getCustomWriteTarget(final Class<?> sourceType, final Class<?> requestedTargetType) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
if (requestedTargetType == null) {
|
||||||
|
return getCustomWriteTarget(sourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customWriteTargetTypes,
|
||||||
|
new Producer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> get() {
|
||||||
return getCustomTarget(sourceType, requestedTargetType, writingPairs);
|
return getCustomTarget(sourceType, requestedTargetType, writingPairs);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether we have a custom conversion registered to write into a Mongo native type. The returned type might
|
* Returns whether we have a custom conversion registered to readTargetWriteLocl into a Mongo native type. The
|
||||||
* be a subclass of the given expected type though.
|
* returned type might be a subclass of the given expected type though.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomWriteTarget(Class<?> sourceType) {
|
public boolean hasCustomWriteTarget(Class<?> sourceType) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
|
||||||
return hasCustomWriteTarget(sourceType, null);
|
return hasCustomWriteTarget(sourceType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether we have a custom conversion registered to write an object of the given source type into an object
|
* Returns whether we have a custom conversion registered to readTargetWriteLocl an object of the given source type
|
||||||
* of the given Mongo native target type.
|
* into an object of the given Mongo native target type.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}.
|
* @param sourceType must not be {@literal null}.
|
||||||
* @param requestedTargetType
|
* @param requestedTargetType
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
public boolean hasCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
|
||||||
return getCustomWriteTarget(sourceType, requestedTargetType) != null;
|
return getCustomWriteTarget(sourceType, requestedTargetType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether we have a custom conversion registered to read the given source into the given target type.
|
* Returns whether we have a custom conversion registered to readTargetReadLock the given source into the given target
|
||||||
|
* type.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @param requestedTargetType must not be {@literal null}
|
* @param requestedTargetType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
public boolean hasCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
|
||||||
Assert.notNull(requestedTargetType);
|
|
||||||
|
|
||||||
return getCustomReadTarget(sourceType, requestedTargetType) != null;
|
return getCustomReadTarget(sourceType, requestedTargetType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
|
* Returns the actual target type for the given {@code sourceType} and {@code requestedTargetType}. Note that the
|
||||||
|
* returned {@link Class} could be an assignable type to the given {@code requestedTargetType}.
|
||||||
|
*
|
||||||
|
* @param sourceType must not be {@literal null}.
|
||||||
|
* @param requestedTargetType can be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Class<?> getCustomReadTarget(final Class<?> sourceType, final Class<?> requestedTargetType) {
|
||||||
|
|
||||||
|
if (requestedTargetType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customReadTargetTypes,
|
||||||
|
new Producer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> get() {
|
||||||
|
return getCustomTarget(sourceType, requestedTargetType, readingPairs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspects the given {@link ConvertiblePair}s for ones that have a source compatible type as source. Additionally
|
||||||
* checks assignability of the target type if one is given.
|
* checks assignability of the target type if one is given.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}.
|
* @param sourceType must not be {@literal null}.
|
||||||
@@ -307,11 +358,15 @@ public class CustomConversions {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
|
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
|
||||||
Iterable<ConvertiblePair> pairs) {
|
Collection<ConvertiblePair> pairs) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
Assert.notNull(sourceType);
|
||||||
Assert.notNull(pairs);
|
Assert.notNull(pairs);
|
||||||
|
|
||||||
|
if (requestedTargetType != null && pairs.contains(new ConvertiblePair(sourceType, requestedTargetType))) {
|
||||||
|
return requestedTargetType;
|
||||||
|
}
|
||||||
|
|
||||||
for (ConvertiblePair typePair : pairs) {
|
for (ConvertiblePair typePair : pairs) {
|
||||||
if (typePair.getSourceType().isAssignableFrom(sourceType)) {
|
if (typePair.getSourceType().isAssignableFrom(sourceType)) {
|
||||||
Class<?> targetType = typePair.getTargetType();
|
Class<?> targetType = typePair.getTargetType();
|
||||||
@@ -325,32 +380,31 @@ public class CustomConversions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the actual target type for the given {@code sourceType} and {@code requestedTargetType}. Note that the
|
* Will try to find a value for the given key in the given cache or produce one using the given {@link Producer} and
|
||||||
* returned {@link Class} could be an assignable type to the given {@code requestedTargetType}.
|
* store it in the cache.
|
||||||
*
|
*
|
||||||
* @param sourceType must not be {@literal null}.
|
* @param key the key to lookup a potentially existing value, must not be {@literal null}.
|
||||||
* @param requestedTargetType can be {@literal null}.
|
* @param cache the cache to find the value in, must not be {@literal null}.
|
||||||
|
* @param producer the {@link Producer} to create values to cache, must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Class<?> getCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
private static <T> Class<?> getOrCreateAndCache(T key, Map<T, CacheValue<Class<?>>> cache, Producer producer) {
|
||||||
|
|
||||||
Assert.notNull(sourceType);
|
CacheValue<Class<?>> cacheValue = cache.get(key);
|
||||||
|
|
||||||
if (requestedTargetType == null) {
|
if (cacheValue != null) {
|
||||||
return null;
|
return cacheValue.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertiblePair lookupKey = new ConvertiblePair(sourceType, requestedTargetType);
|
Class<?> type = producer.get();
|
||||||
CacheValue readTargetTypeValue = customReadTargetTypes.get(lookupKey);
|
cache.put(key, CacheValue.<Class<?>> ofNullable(type));
|
||||||
|
|
||||||
if (readTargetTypeValue != null) {
|
return type;
|
||||||
return readTargetTypeValue.getType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readTargetTypeValue = CacheValue.of(getCustomTarget(sourceType, requestedTargetType, readingPairs));
|
private interface Producer {
|
||||||
CacheValue cacheValue = customReadTargetTypes.putIfAbsent(lookupKey, readTargetTypeValue);
|
|
||||||
|
|
||||||
return cacheValue != null ? cacheValue.getType() : readTargetTypeValue.getType();
|
Class<?> get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
@@ -370,30 +424,4 @@ public class CustomConversions {
|
|||||||
return source.toString();
|
return source.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper to safely store {@literal null} values in the type cache.
|
|
||||||
*
|
|
||||||
* @author Patryk Wasik
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
private static class CacheValue {
|
|
||||||
|
|
||||||
private static final CacheValue ABSENT = new CacheValue(null);
|
|
||||||
|
|
||||||
private final Class<?> type;
|
|
||||||
|
|
||||||
public CacheValue(Class<?> type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CacheValue of(Class<?> type) {
|
|
||||||
return type == null ? ABSENT : new CacheValue(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 the original author or authors.
|
* Copyright 2013-2015 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.DBObject;
|
|||||||
*/
|
*/
|
||||||
class DBObjectAccessor {
|
class DBObjectAccessor {
|
||||||
|
|
||||||
private final DBObject dbObject;
|
private final BasicDBObject dbObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link DBObjectAccessor} for the given {@link DBObject}.
|
* Creates a new {@link DBObjectAccessor} for the given {@link DBObject}.
|
||||||
@@ -46,7 +46,7 @@ class DBObjectAccessor {
|
|||||||
Assert.notNull(dbObject, "DBObject must not be null!");
|
Assert.notNull(dbObject, "DBObject must not be null!");
|
||||||
Assert.isInstanceOf(BasicDBObject.class, dbObject, "Given DBObject must be a BasicDBObject!");
|
Assert.isInstanceOf(BasicDBObject.class, dbObject, "Given DBObject must be a BasicDBObject!");
|
||||||
|
|
||||||
this.dbObject = dbObject;
|
this.dbObject = (BasicDBObject) dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,6 +62,11 @@ class DBObjectAccessor {
|
|||||||
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
|
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
|
||||||
String fieldName = prop.getFieldName();
|
String fieldName = prop.getFieldName();
|
||||||
|
|
||||||
|
if (!fieldName.contains(".")) {
|
||||||
|
dbObject.put(fieldName, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||||
DBObject dbObject = this.dbObject;
|
DBObject dbObject = this.dbObject;
|
||||||
|
|
||||||
@@ -87,12 +92,16 @@ class DBObjectAccessor {
|
|||||||
* @param property must not be {@literal null}.
|
* @param property must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Object get(MongoPersistentProperty property) {
|
public Object get(MongoPersistentProperty property) {
|
||||||
|
|
||||||
String fieldName = property.getFieldName();
|
String fieldName = property.getFieldName();
|
||||||
|
|
||||||
|
if (!fieldName.contains(".")) {
|
||||||
|
return this.dbObject.get(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||||
Map<Object, Object> source = this.dbObject.toMap();
|
Map<String, Object> source = this.dbObject;
|
||||||
Object result = null;
|
Object result = null;
|
||||||
|
|
||||||
while (source != null && parts.hasNext()) {
|
while (source != null && parts.hasNext()) {
|
||||||
@@ -108,14 +117,14 @@ class DBObjectAccessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Map<Object, Object> getAsMap(Object source) {
|
private Map<String, Object> getAsMap(Object source) {
|
||||||
|
|
||||||
if (source instanceof BasicDBObject) {
|
if (source instanceof BasicDBObject) {
|
||||||
return ((DBObject) source).toMap();
|
return (BasicDBObject) source;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source instanceof Map) {
|
if (source instanceof Map) {
|
||||||
return (Map<Object, Object>) source;
|
return (Map<String, Object>) source;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2014 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.core.geo;
|
package org.springframework.data.mongodb.core.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for {@link Metric}s that can be applied to a base scale.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metric}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public interface DbRefProxyHandler {
|
||||||
public interface Metric extends org.springframework.data.geo.Metric {}
|
|
||||||
|
Object populateId(MongoPersistentProperty property, DBRef source, Object proxy);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2014 the original author or authors.
|
* Copyright 2013-2015 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,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
|
|||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import com.mongodb.DBRef;
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +26,7 @@ import com.mongodb.DBRef;
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public interface DbRefResolver {
|
public interface DbRefResolver {
|
||||||
@@ -39,7 +41,8 @@ public interface DbRefResolver {
|
|||||||
* @param callback will never be {@literal null}.
|
* @param callback will never be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback);
|
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||||
|
DbRefProxyHandler proxyHandler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link DBRef} instance for the given {@link org.springframework.data.mongodb.core.mapping.DBRef}
|
* Creates a {@link DBRef} instance for the given {@link org.springframework.data.mongodb.core.mapping.DBRef}
|
||||||
@@ -52,4 +55,13 @@ public interface DbRefResolver {
|
|||||||
*/
|
*/
|
||||||
DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity<?> entity,
|
DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity<?> entity,
|
||||||
Object id);
|
Object id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually loads the {@link DBRef} from the datasource.
|
||||||
|
*
|
||||||
|
* @param dbRef must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
DBObject fetch(DBRef dbRef);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
|
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||||
|
import org.springframework.data.mapping.model.SpELContext;
|
||||||
|
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
class DefaultDbRefProxyHandler implements DbRefProxyHandler {
|
||||||
|
|
||||||
|
private final SpELContext spELContext;
|
||||||
|
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
|
private final ValueResolver resolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param spELContext must not be {@literal null}.
|
||||||
|
* @param conversionService must not be {@literal null}.
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public DefaultDbRefProxyHandler(SpELContext spELContext,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext, ValueResolver resolver) {
|
||||||
|
|
||||||
|
this.spELContext = spELContext;
|
||||||
|
this.mappingContext = mappingContext;
|
||||||
|
this.resolver = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.DbRefProxyHandler#populateId(com.mongodb.DBRef, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object populateId(MongoPersistentProperty property, DBRef source, Object proxy) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(property);
|
||||||
|
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||||
|
|
||||||
|
if (idProperty.usePropertyAccess()) {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext);
|
||||||
|
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(proxy);
|
||||||
|
|
||||||
|
DBObject object = new BasicDBObject(idProperty.getFieldName(), source.getId());
|
||||||
|
ObjectPath objectPath = ObjectPath.ROOT.push(proxy, entity, null);
|
||||||
|
accessor.setProperty(idProperty, resolver.getValueInternal(idProperty, object, evaluator, objectPath));
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2014 the original author or authors.
|
* Copyright 2013-2015 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,26 +25,22 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
import org.objenesis.Objenesis;
|
|
||||||
import org.objenesis.ObjenesisStd;
|
|
||||||
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
import org.springframework.cglib.proxy.Callback;
|
import org.springframework.cglib.proxy.Callback;
|
||||||
import org.springframework.cglib.proxy.Enhancer;
|
import org.springframework.cglib.proxy.Enhancer;
|
||||||
import org.springframework.cglib.proxy.Factory;
|
import org.springframework.cglib.proxy.Factory;
|
||||||
import org.springframework.cglib.proxy.MethodProxy;
|
import org.springframework.cglib.proxy.MethodProxy;
|
||||||
import org.springframework.core.SpringVersion;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.mongodb.LazyLoadingException;
|
import org.springframework.data.mongodb.LazyLoadingException;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
import org.springframework.objenesis.ObjenesisStd;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DBObject;
|
||||||
import com.mongodb.DBRef;
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,15 +49,14 @@ import com.mongodb.DBRef;
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public class DefaultDbRefResolver implements DbRefResolver {
|
public class DefaultDbRefResolver implements DbRefResolver {
|
||||||
|
|
||||||
private static final boolean IS_SPRING_4_OR_BETTER = SpringVersion.getVersion().startsWith("4");
|
|
||||||
private static final boolean OBJENESIS_PRESENT = ClassUtils.isPresent("org.objenesis.Objenesis", null);
|
|
||||||
|
|
||||||
private final MongoDbFactory mongoDbFactory;
|
private final MongoDbFactory mongoDbFactory;
|
||||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||||
|
private final ObjenesisStd objenesis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}.
|
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}.
|
||||||
@@ -74,6 +69,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
|
|
||||||
this.mongoDbFactory = mongoDbFactory;
|
this.mongoDbFactory = mongoDbFactory;
|
||||||
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||||
|
this.objenesis = new ObjenesisStd(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -81,13 +77,14 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
|
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||||
|
DbRefProxyHandler handler) {
|
||||||
|
|
||||||
Assert.notNull(property, "Property must not be null!");
|
Assert.notNull(property, "Property must not be null!");
|
||||||
Assert.notNull(callback, "Callback must not be null!");
|
Assert.notNull(callback, "Callback must not be null!");
|
||||||
|
|
||||||
if (isLazyDbRef(property)) {
|
if (isLazyDbRef(property)) {
|
||||||
return createLazyLoadingProxy(property, dbref, callback);
|
return createLazyLoadingProxy(property, dbref, callback, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback.resolve(property);
|
return callback.resolve(property);
|
||||||
@@ -100,11 +97,16 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
@Override
|
@Override
|
||||||
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
|
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
|
||||||
MongoPersistentEntity<?> entity, Object id) {
|
MongoPersistentEntity<?> entity, Object id) {
|
||||||
|
return new DBRef(entity.getCollection(), id);
|
||||||
|
}
|
||||||
|
|
||||||
DB db = mongoDbFactory.getDb();
|
/*
|
||||||
db = annotation != null && StringUtils.hasText(annotation.db()) ? mongoDbFactory.getDb(annotation.db()) : db;
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
|
||||||
return new DBRef(db, entity.getCollection(), id);
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject fetch(DBRef dbRef) {
|
||||||
|
return ReflectiveDBRefResolver.fetch(mongoDbFactory.getDb(), dbRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,34 +118,47 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
* @param callback must not be {@literal null}.
|
* @param callback must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||||
|
DbRefProxyHandler handler) {
|
||||||
|
|
||||||
|
Class<?> propertyType = property.getType();
|
||||||
|
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||||
|
|
||||||
|
if (!propertyType.isInterface()) {
|
||||||
|
|
||||||
|
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType));
|
||||||
|
factory.setCallbacks(new Callback[] { interceptor });
|
||||||
|
|
||||||
|
return handler.populateId(property, dbref, factory);
|
||||||
|
}
|
||||||
|
|
||||||
ProxyFactory proxyFactory = new ProxyFactory();
|
ProxyFactory proxyFactory = new ProxyFactory();
|
||||||
Class<?> propertyType = property.getType();
|
|
||||||
|
|
||||||
for (Class<?> type : propertyType.getInterfaces()) {
|
for (Class<?> type : propertyType.getInterfaces()) {
|
||||||
proxyFactory.addInterface(type);
|
proxyFactory.addInterface(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
|
||||||
|
|
||||||
proxyFactory.addInterface(LazyLoadingProxy.class);
|
proxyFactory.addInterface(LazyLoadingProxy.class);
|
||||||
|
|
||||||
if (propertyType.isInterface()) {
|
|
||||||
proxyFactory.addInterface(propertyType);
|
proxyFactory.addInterface(propertyType);
|
||||||
proxyFactory.addAdvice(interceptor);
|
proxyFactory.addAdvice(interceptor);
|
||||||
return proxyFactory.getProxy();
|
|
||||||
|
return handler.populateId(property, dbref, proxyFactory.getProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyFactory.setProxyTargetClass(true);
|
/**
|
||||||
proxyFactory.setTargetClass(propertyType);
|
* Returns the CGLib enhanced type for the given source type.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Class<?> getEnhancedTypeFor(Class<?> type) {
|
||||||
|
|
||||||
if (IS_SPRING_4_OR_BETTER || !OBJENESIS_PRESENT) {
|
Enhancer enhancer = new Enhancer();
|
||||||
proxyFactory.addAdvice(interceptor);
|
enhancer.setSuperclass(type);
|
||||||
return proxyFactory.getProxy();
|
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||||
}
|
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class });
|
||||||
|
|
||||||
return ObjenesisProxyEnhancer.enhanceAndGet(proxyFactory, propertyType, interceptor);
|
return enhancer.createClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,11 +178,12 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
||||||
Serializable {
|
Serializable {
|
||||||
|
|
||||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD;
|
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
|
||||||
|
|
||||||
private final DbRefResolverCallback callback;
|
private final DbRefResolverCallback callback;
|
||||||
private final MongoPersistentProperty property;
|
private final MongoPersistentProperty property;
|
||||||
@@ -179,8 +195,9 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("initialize");
|
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("getTarget");
|
||||||
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||||
|
FINALIZE_METHOD = Object.class.getDeclaredMethod("finalize");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -244,6 +261,11 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
if (ReflectionUtils.isHashCodeMethod(method)) {
|
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||||
return proxyHashCode(proxy);
|
return proxyHashCode(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DATAMONGO-1076 - finalize methods should not trigger proxy initialization
|
||||||
|
if (FINALIZE_METHOD.equals(method)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object target = ensureResolved();
|
Object target = ensureResolved();
|
||||||
@@ -265,7 +287,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
|
|
||||||
StringBuilder description = new StringBuilder();
|
StringBuilder description = new StringBuilder();
|
||||||
if (dbref != null) {
|
if (dbref != null) {
|
||||||
description.append(dbref.getRef());
|
description.append(dbref.getCollectionName());
|
||||||
description.append(":");
|
description.append(":");
|
||||||
description.append(dbref.getId());
|
description.append(dbref.getId());
|
||||||
} else {
|
} else {
|
||||||
@@ -372,27 +394,4 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Static class to accomodate optional dependency on Objenesis.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
*/
|
|
||||||
private static class ObjenesisProxyEnhancer {
|
|
||||||
|
|
||||||
private static final Objenesis OBJENESIS = new ObjenesisStd(true);
|
|
||||||
|
|
||||||
public static Object enhanceAndGet(ProxyFactory proxyFactory, Class<?> type,
|
|
||||||
org.springframework.cglib.proxy.MethodInterceptor interceptor) {
|
|
||||||
|
|
||||||
Enhancer enhancer = new Enhancer();
|
|
||||||
enhancer.setSuperclass(type);
|
|
||||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
|
||||||
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class });
|
|
||||||
|
|
||||||
Factory factory = (Factory) OBJENESIS.newInstance(enhancer.createClass());
|
|
||||||
factory.setCallbacks(new Callback[] { interceptor });
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link DbRefResolverCallback}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
class DefaultDbRefResolverCallback implements DbRefResolverCallback {
|
||||||
|
|
||||||
|
private final DBObject surroundingObject;
|
||||||
|
private final ObjectPath path;
|
||||||
|
private final ValueResolver resolver;
|
||||||
|
private final SpELExpressionEvaluator evaluator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link DBObject}, {@link ObjectPath},
|
||||||
|
* {@link ValueResolver} and {@link SpELExpressionEvaluator}.
|
||||||
|
*
|
||||||
|
* @param surroundingObject must not be {@literal null}.
|
||||||
|
* @param path must not be {@literal null}.
|
||||||
|
* @param evaluator must not be {@literal null}.
|
||||||
|
* @param resolver must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public DefaultDbRefResolverCallback(DBObject surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
|
||||||
|
ValueResolver resolver) {
|
||||||
|
|
||||||
|
this.surroundingObject = surroundingObject;
|
||||||
|
this.path = path;
|
||||||
|
this.resolver = resolver;
|
||||||
|
this.evaluator = evaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.DbRefResolverCallback#resolve(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object resolve(MongoPersistentProperty property) {
|
||||||
|
return resolver.getValueInternal(property, surroundingObject, evaluator, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2014 the original author or authors.
|
* Copyright 2014-2015 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.
|
||||||
@@ -30,9 +30,18 @@ import org.springframework.data.geo.Metrics;
|
|||||||
import org.springframework.data.geo.Point;
|
import org.springframework.data.geo.Point;
|
||||||
import org.springframework.data.geo.Polygon;
|
import org.springframework.data.geo.Polygon;
|
||||||
import org.springframework.data.geo.Shape;
|
import org.springframework.data.geo.Shape;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJson;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonGeometryCollection;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonMultiLineString;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||||
|
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
|
||||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||||
import org.springframework.data.mongodb.core.query.GeoCommand;
|
import org.springframework.data.mongodb.core.query.GeoCommand;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
import com.mongodb.BasicDBList;
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
@@ -43,6 +52,7 @@ import com.mongodb.DBObject;
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
abstract class GeoConverters {
|
abstract class GeoConverters {
|
||||||
@@ -63,16 +73,24 @@ abstract class GeoConverters {
|
|||||||
BoxToDbObjectConverter.INSTANCE //
|
BoxToDbObjectConverter.INSTANCE //
|
||||||
, PolygonToDbObjectConverter.INSTANCE //
|
, PolygonToDbObjectConverter.INSTANCE //
|
||||||
, CircleToDbObjectConverter.INSTANCE //
|
, CircleToDbObjectConverter.INSTANCE //
|
||||||
, LegacyCircleToDbObjectConverter.INSTANCE //
|
|
||||||
, SphereToDbObjectConverter.INSTANCE //
|
, SphereToDbObjectConverter.INSTANCE //
|
||||||
, DbObjectToBoxConverter.INSTANCE //
|
, DbObjectToBoxConverter.INSTANCE //
|
||||||
, DbObjectToPolygonConverter.INSTANCE //
|
, DbObjectToPolygonConverter.INSTANCE //
|
||||||
, DbObjectToCircleConverter.INSTANCE //
|
, DbObjectToCircleConverter.INSTANCE //
|
||||||
, DbObjectToLegacyCircleConverter.INSTANCE //
|
|
||||||
, DbObjectToSphereConverter.INSTANCE //
|
, DbObjectToSphereConverter.INSTANCE //
|
||||||
, DbObjectToPointConverter.INSTANCE //
|
, DbObjectToPointConverter.INSTANCE //
|
||||||
, PointToDbObjectConverter.INSTANCE //
|
, PointToDbObjectConverter.INSTANCE //
|
||||||
, GeoCommandToDbObjectConverter.INSTANCE);
|
, GeoCommandToDbObjectConverter.INSTANCE //
|
||||||
|
, GeoJsonToDbObjectConverter.INSTANCE //
|
||||||
|
, GeoJsonPointToDbObjectConverter.INSTANCE //
|
||||||
|
, GeoJsonPolygonToDbObjectConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonPointConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonPolygonConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonLineStringConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonMultiLineStringConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonMultiPointConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonMultiPolygonConverter.INSTANCE //
|
||||||
|
, DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +100,7 @@ abstract class GeoConverters {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
public static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
|
static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -91,13 +109,11 @@ abstract class GeoConverters {
|
|||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public Point convert(DBObject source) {
|
public Point convert(DBObject source) {
|
||||||
|
|
||||||
Assert.isTrue(source.keySet().size() == 2, "Source must contain 2 elements");
|
Assert.isTrue(source.keySet().size() == 2, "Source must contain 2 elements");
|
||||||
|
|
||||||
return source == null ? null : new org.springframework.data.mongodb.core.geo.Point((Double) source.get("x"),
|
return source == null ? null : new Point((Double) source.get("x"), (Double) source.get("y"));
|
||||||
(Double) source.get("y"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +123,7 @@ abstract class GeoConverters {
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
|
static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -128,7 +144,7 @@ abstract class GeoConverters {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
public static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
|
static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -151,13 +167,13 @@ abstract class GeoConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Box}.
|
* Converts a {@link BasicDBList} into a {@link Box}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
public static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
|
static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -166,7 +182,6 @@ abstract class GeoConverters {
|
|||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public Box convert(DBObject source) {
|
public Box convert(DBObject source) {
|
||||||
|
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@@ -176,7 +191,7 @@ abstract class GeoConverters {
|
|||||||
Point first = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("first"));
|
Point first = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("first"));
|
||||||
Point second = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("second"));
|
Point second = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("second"));
|
||||||
|
|
||||||
return new org.springframework.data.mongodb.core.geo.Box(first, second);
|
return new Box(first, second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +201,7 @@ abstract class GeoConverters {
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
|
static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -210,13 +225,13 @@ abstract class GeoConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a {@link DBObject} into a {@link org.springframework.data.mongodb.core.geo.Circle}.
|
* Converts a {@link DBObject} into a {@link Circle}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
public static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
|
static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -251,78 +266,13 @@ abstract class GeoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a {@link Circle} into a {@link BasicDBList}.
|
|
||||||
*
|
|
||||||
* @author Thomas Darimont
|
|
||||||
* @since 1.5
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static enum LegacyCircleToDbObjectConverter implements
|
|
||||||
Converter<org.springframework.data.mongodb.core.geo.Circle, DBObject> {
|
|
||||||
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DBObject convert(org.springframework.data.mongodb.core.geo.Circle source) {
|
|
||||||
|
|
||||||
if (source == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBObject result = new BasicDBObject();
|
|
||||||
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
|
|
||||||
result.put("radius", source.getRadius());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Circle}.
|
|
||||||
*
|
|
||||||
* @author Thomas Darimont
|
|
||||||
* @since 1.5
|
|
||||||
*/
|
|
||||||
@ReadingConverter
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static enum DbObjectToLegacyCircleConverter implements
|
|
||||||
Converter<DBObject, org.springframework.data.mongodb.core.geo.Circle> {
|
|
||||||
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public org.springframework.data.mongodb.core.geo.Circle convert(DBObject source) {
|
|
||||||
|
|
||||||
if (source == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBObject centerSource = (DBObject) source.get("center");
|
|
||||||
Double radius = (Double) source.get("radius");
|
|
||||||
|
|
||||||
Assert.notNull(centerSource, "Center must not be null!");
|
|
||||||
Assert.notNull(radius, "Radius must not be null!");
|
|
||||||
|
|
||||||
Point center = DbObjectToPointConverter.INSTANCE.convert(centerSource);
|
|
||||||
return new org.springframework.data.mongodb.core.geo.Circle(center, radius);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a {@link Sphere} into a {@link BasicDBList}.
|
* Converts a {@link Sphere} into a {@link BasicDBList}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
|
static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -352,7 +302,7 @@ abstract class GeoConverters {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
public static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
|
static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -393,7 +343,7 @@ abstract class GeoConverters {
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
|
static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -422,13 +372,13 @@ abstract class GeoConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Polygon}.
|
* Converts a {@link BasicDBList} into a {@link Polygon}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
public static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
|
static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -437,7 +387,7 @@ abstract class GeoConverters {
|
|||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public Polygon convert(DBObject source) {
|
public Polygon convert(DBObject source) {
|
||||||
|
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@@ -453,7 +403,7 @@ abstract class GeoConverters {
|
|||||||
newPoints.add(DbObjectToPointConverter.INSTANCE.convert(element));
|
newPoints.add(DbObjectToPointConverter.INSTANCE.convert(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new org.springframework.data.mongodb.core.geo.Polygon(newPoints);
|
return new Polygon(newPoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +413,7 @@ abstract class GeoConverters {
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
|
static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -472,7 +422,7 @@ abstract class GeoConverters {
|
|||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("rawtypes")
|
||||||
public DBObject convert(GeoCommand source) {
|
public DBObject convert(GeoCommand source) {
|
||||||
|
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@@ -483,6 +433,10 @@ abstract class GeoConverters {
|
|||||||
|
|
||||||
Shape shape = source.getShape();
|
Shape shape = source.getShape();
|
||||||
|
|
||||||
|
if (shape instanceof GeoJson) {
|
||||||
|
return GeoJsonToDbObjectConverter.INSTANCE.convert((GeoJson) shape);
|
||||||
|
}
|
||||||
|
|
||||||
if (shape instanceof Box) {
|
if (shape instanceof Box) {
|
||||||
|
|
||||||
argument.add(toList(((Box) shape).getFirst()));
|
argument.add(toList(((Box) shape).getFirst()));
|
||||||
@@ -493,10 +447,10 @@ abstract class GeoConverters {
|
|||||||
argument.add(toList(((Circle) shape).getCenter()));
|
argument.add(toList(((Circle) shape).getCenter()));
|
||||||
argument.add(((Circle) shape).getRadius().getNormalizedValue());
|
argument.add(((Circle) shape).getRadius().getNormalizedValue());
|
||||||
|
|
||||||
} else if (shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
|
} else if (shape instanceof Circle) {
|
||||||
|
|
||||||
argument.add(toList(((org.springframework.data.mongodb.core.geo.Circle) shape).getCenter()));
|
argument.add(toList(((Circle) shape).getCenter()));
|
||||||
argument.add(((org.springframework.data.mongodb.core.geo.Circle) shape).getRadius());
|
argument.add(((Circle) shape).getRadius());
|
||||||
|
|
||||||
} else if (shape instanceof Polygon) {
|
} else if (shape instanceof Polygon) {
|
||||||
|
|
||||||
@@ -514,7 +468,377 @@ abstract class GeoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
static enum GeoJsonToDbObjectConverter implements Converter<GeoJson, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(GeoJson source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject dbo = new BasicDBObject("type", source.getType());
|
||||||
|
|
||||||
|
if (source instanceof GeoJsonGeometryCollection) {
|
||||||
|
|
||||||
|
BasicDBList dbl = new BasicDBList();
|
||||||
|
|
||||||
|
for (GeoJson geometry : ((GeoJsonGeometryCollection) source).getCoordinates()) {
|
||||||
|
dbl.add(convert(geometry));
|
||||||
|
}
|
||||||
|
|
||||||
|
dbo.put("geometries", dbl);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
dbo.put("coordinates", convertIfNecessarry(source.getCoordinates()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object convertIfNecessarry(Object candidate) {
|
||||||
|
|
||||||
|
if (candidate instanceof GeoJson) {
|
||||||
|
return convertIfNecessarry(((GeoJson) candidate).getCoordinates());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate instanceof Iterable) {
|
||||||
|
|
||||||
|
BasicDBList dbl = new BasicDBList();
|
||||||
|
|
||||||
|
for (Object element : (Iterable) candidate) {
|
||||||
|
dbl.add(convertIfNecessarry(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate instanceof Point) {
|
||||||
|
return toList((Point) candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum GeoJsonPointToDbObjectConverter implements Converter<GeoJsonPoint, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(GeoJsonPoint source) {
|
||||||
|
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum GeoJsonPolygonToDbObjectConverter implements Converter<GeoJsonPolygon, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(GeoJsonPolygon source) {
|
||||||
|
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonPointConverter implements Converter<DBObject, GeoJsonPoint> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public GeoJsonPoint convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Point"),
|
||||||
|
String.format("Cannot convert type '%s' to Point.", source.get("type")));
|
||||||
|
|
||||||
|
List<Double> dbl = (List<Double>) source.get("coordinates");
|
||||||
|
return new GeoJsonPoint(dbl.get(0).doubleValue(), dbl.get(1).doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonPolygonConverter implements Converter<DBObject, GeoJsonPolygon> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GeoJsonPolygon convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Polygon"),
|
||||||
|
String.format("Cannot convert type '%s' to Polygon.", source.get("type")));
|
||||||
|
|
||||||
|
return toGeoJsonPolygon((BasicDBList) source.get("coordinates"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonMultiPolygonConverter implements Converter<DBObject, GeoJsonMultiPolygon> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GeoJsonMultiPolygon convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPolygon"),
|
||||||
|
String.format("Cannot convert type '%s' to MultiPolygon.", source.get("type")));
|
||||||
|
|
||||||
|
BasicDBList dbl = (BasicDBList) source.get("coordinates");
|
||||||
|
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>();
|
||||||
|
|
||||||
|
for (Object polygon : dbl) {
|
||||||
|
polygones.add(toGeoJsonPolygon((BasicDBList) polygon));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GeoJsonMultiPolygon(polygones);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonLineStringConverter implements Converter<DBObject, GeoJsonLineString> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GeoJsonLineString convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "LineString"),
|
||||||
|
String.format("Cannot convert type '%s' to LineString.", source.get("type")));
|
||||||
|
|
||||||
|
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||||
|
|
||||||
|
return new GeoJsonLineString(toListOfPoint(cords));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonMultiPointConverter implements Converter<DBObject, GeoJsonMultiPoint> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GeoJsonMultiPoint convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPoint"),
|
||||||
|
String.format("Cannot convert type '%s' to MultiPoint.", source.get("type")));
|
||||||
|
|
||||||
|
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||||
|
|
||||||
|
return new GeoJsonMultiPoint(toListOfPoint(cords));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonMultiLineStringConverter implements Converter<DBObject, GeoJsonMultiLineString> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GeoJsonMultiLineString convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiLineString"),
|
||||||
|
String.format("Cannot convert type '%s' to MultiLineString.", source.get("type")));
|
||||||
|
|
||||||
|
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>();
|
||||||
|
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||||
|
|
||||||
|
for (Object line : cords) {
|
||||||
|
lines.add(new GeoJsonLineString(toListOfPoint((BasicDBList) line)));
|
||||||
|
}
|
||||||
|
return new GeoJsonMultiLineString(lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static enum DbObjectToGeoJsonGeometryCollectionConverter implements Converter<DBObject, GeoJsonGeometryCollection> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Override
|
||||||
|
public GeoJsonGeometryCollection convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "GeometryCollection"),
|
||||||
|
String.format("Cannot convert type '%s' to GeometryCollection.", source.get("type")));
|
||||||
|
|
||||||
|
List<GeoJson<?>> geometries = new ArrayList<GeoJson<?>>();
|
||||||
|
for (Object o : (List) source.get("geometries")) {
|
||||||
|
geometries.add(convertGeometries((DBObject) o));
|
||||||
|
}
|
||||||
|
return new GeoJsonGeometryCollection(geometries);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GeoJson<?> convertGeometries(DBObject source) {
|
||||||
|
|
||||||
|
Object type = source.get("type");
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "Point")) {
|
||||||
|
return DbObjectToGeoJsonPointConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "MultiPoint")) {
|
||||||
|
return DbObjectToGeoJsonMultiPointConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "LineString")) {
|
||||||
|
return DbObjectToGeoJsonLineStringConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "MultiLineString")) {
|
||||||
|
return DbObjectToGeoJsonMultiLineStringConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "Polygon")) {
|
||||||
|
return DbObjectToGeoJsonPolygonConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
if (ObjectUtils.nullSafeEquals(type, "MultiPolygon")) {
|
||||||
|
return DbObjectToGeoJsonMultiPolygonConverter.INSTANCE.convert(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot convert unknown GeoJson type %s", type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static List<Double> toList(Point point) {
|
static List<Double> toList(Point point) {
|
||||||
return Arrays.asList(point.getX(), point.getY());
|
return Arrays.asList(point.getX(), point.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPoint}s.
|
||||||
|
*
|
||||||
|
* @param listOfCoordinatePairs
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static List<Point> toListOfPoint(BasicDBList listOfCoordinatePairs) {
|
||||||
|
|
||||||
|
List<Point> points = new ArrayList<Point>();
|
||||||
|
|
||||||
|
for (Object point : listOfCoordinatePairs) {
|
||||||
|
|
||||||
|
Assert.isInstanceOf(List.class, point);
|
||||||
|
|
||||||
|
List<Double> coordinatesList = (List<Double>) point;
|
||||||
|
|
||||||
|
points.add(new GeoJsonPoint(coordinatesList.get(0).doubleValue(), coordinatesList.get(1).doubleValue()));
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPolygon}.
|
||||||
|
*
|
||||||
|
* @param dbList
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static GeoJsonPolygon toGeoJsonPolygon(BasicDBList dbList) {
|
||||||
|
return new GeoJsonPolygon(toListOfPoint((BasicDBList) dbList.get(0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.mongodb.DBRef;
|
|||||||
* Allows direct interaction with the underlying {@link LazyLoadingInterceptor}.
|
* Allows direct interaction with the underlying {@link LazyLoadingInterceptor}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public interface LazyLoadingProxy {
|
public interface LazyLoadingProxy {
|
||||||
@@ -33,7 +34,7 @@ public interface LazyLoadingProxy {
|
|||||||
* @return
|
* @return
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
Object initialize();
|
Object getTarget();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link DBRef} represented by this {@link LazyLoadingProxy}, may be null.
|
* Returns the {@link DBRef} represented by this {@link LazyLoadingProxy}, may be null.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 by the original author(s).
|
* Copyright 2011-2015 by the original author(s).
|
||||||
*
|
*
|
||||||
* 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,16 +31,17 @@ import org.springframework.context.ApplicationContext;
|
|||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.core.convert.ConversionException;
|
import org.springframework.core.convert.ConversionException;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.data.convert.CollectionFactory;
|
import org.springframework.data.convert.CollectionFactory;
|
||||||
import org.springframework.data.convert.EntityInstantiator;
|
import org.springframework.data.convert.EntityInstantiator;
|
||||||
import org.springframework.data.convert.TypeMapper;
|
import org.springframework.data.convert.TypeMapper;
|
||||||
import org.springframework.data.mapping.Association;
|
import org.springframework.data.mapping.Association;
|
||||||
import org.springframework.data.mapping.AssociationHandler;
|
import org.springframework.data.mapping.AssociationHandler;
|
||||||
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||||
import org.springframework.data.mapping.PropertyHandler;
|
import org.springframework.data.mapping.PropertyHandler;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.BeanWrapper;
|
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||||
@@ -56,6 +57,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
|||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
import com.mongodb.BasicDBList;
|
||||||
@@ -73,7 +75,9 @@ import com.mongodb.DBRef;
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware, ValueResolver {
|
||||||
|
|
||||||
|
private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s! Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions. Parent object was: %4$s";
|
||||||
|
|
||||||
protected static final Logger LOGGER = LoggerFactory.getLogger(MappingMongoConverter.class);
|
protected static final Logger LOGGER = LoggerFactory.getLogger(MappingMongoConverter.class);
|
||||||
|
|
||||||
@@ -81,6 +85,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||||
protected final QueryMapper idMapper;
|
protected final QueryMapper idMapper;
|
||||||
protected final DbRefResolver dbRefResolver;
|
protected final DbRefResolver dbRefResolver;
|
||||||
|
|
||||||
protected ApplicationContext applicationContext;
|
protected ApplicationContext applicationContext;
|
||||||
protected MongoTypeMapper typeMapper;
|
protected MongoTypeMapper typeMapper;
|
||||||
protected String mapKeyDotReplacement = null;
|
protected String mapKeyDotReplacement = null;
|
||||||
@@ -93,11 +98,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* @param mongoDbFactory must not be {@literal null}.
|
* @param mongoDbFactory must not be {@literal null}.
|
||||||
* @param mappingContext must not be {@literal null}.
|
* @param mappingContext must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
||||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
|
||||||
super(ConversionServiceFactory.createDefaultConversionService());
|
super(new DefaultConversionService());
|
||||||
|
|
||||||
Assert.notNull(dbRefResolver, "DbRefResolver must not be null!");
|
Assert.notNull(dbRefResolver, "DbRefResolver must not be null!");
|
||||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||||
@@ -184,11 +188,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected <S extends Object> S read(TypeInformation<S> type, DBObject dbo) {
|
protected <S extends Object> S read(TypeInformation<S> type, DBObject dbo) {
|
||||||
return read(type, dbo, null);
|
return read(type, dbo, ObjectPath.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <S extends Object> S read(TypeInformation<S> type, DBObject dbo, Object parent) {
|
private <S extends Object> S read(TypeInformation<S> type, DBObject dbo, ObjectPath path) {
|
||||||
|
|
||||||
if (null == dbo) {
|
if (null == dbo) {
|
||||||
return null;
|
return null;
|
||||||
@@ -206,11 +210,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeToUse.isCollectionLike() && dbo instanceof BasicDBList) {
|
if (typeToUse.isCollectionLike() && dbo instanceof BasicDBList) {
|
||||||
return (S) readCollectionOrArray(typeToUse, (BasicDBList) dbo, parent);
|
return (S) readCollectionOrArray(typeToUse, (BasicDBList) dbo, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeToUse.isMap()) {
|
if (typeToUse.isMap()) {
|
||||||
return (S) readMap(typeToUse, dbo, parent);
|
return (S) readMap(typeToUse, dbo, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbo instanceof BasicDBList) {
|
||||||
|
throw new MappingException(String.format(INCOMPATIBLE_TYPES, dbo, BasicDBList.class, typeToUse.getType(), path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve persistent entity info
|
// Retrieve persistent entity info
|
||||||
@@ -220,41 +228,57 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
throw new MappingException("No mapping metadata found for " + rawType.getName());
|
throw new MappingException("No mapping metadata found for " + rawType.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return read(persistentEntity, dbo, parent);
|
return read(persistentEntity, dbo, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(MongoPersistentEntity<?> entity,
|
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(MongoPersistentEntity<?> entity,
|
||||||
DBObject source, DefaultSpELExpressionEvaluator evaluator, Object parent) {
|
DBObject source, DefaultSpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||||
|
|
||||||
MongoDbPropertyValueProvider provider = new MongoDbPropertyValueProvider(source, evaluator, parent);
|
MongoDbPropertyValueProvider provider = new MongoDbPropertyValueProvider(source, evaluator, path);
|
||||||
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<MongoPersistentProperty>(
|
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<MongoPersistentProperty>(
|
||||||
entity, provider, parent);
|
entity, provider, path.getCurrentObject());
|
||||||
|
|
||||||
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider,
|
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider, path);
|
||||||
parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final Object parent) {
|
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final ObjectPath path) {
|
||||||
|
|
||||||
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(dbo, spELContext);
|
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(dbo, spELContext);
|
||||||
|
|
||||||
ParameterValueProvider<MongoPersistentProperty> provider = getParameterProvider(entity, dbo, evaluator, parent);
|
ParameterValueProvider<MongoPersistentProperty> provider = getParameterProvider(entity, dbo, evaluator, path);
|
||||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||||
S instance = instantiator.createInstance(entity, provider);
|
S instance = instantiator.createInstance(entity, provider);
|
||||||
|
|
||||||
final BeanWrapper<S> wrapper = BeanWrapper.create(instance, conversionService);
|
final PersistentPropertyAccessor accessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(instance),
|
||||||
final S result = wrapper.getBean();
|
conversionService);
|
||||||
|
|
||||||
|
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||||
|
final S result = instance;
|
||||||
|
|
||||||
|
// make sure id property is set before all other properties
|
||||||
|
Object idValue = null;
|
||||||
|
|
||||||
|
if (idProperty != null) {
|
||||||
|
idValue = getValueInternal(idProperty, dbo, evaluator, path);
|
||||||
|
accessor.setProperty(idProperty, idValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ObjectPath currentPath = path.push(result, entity, idValue);
|
||||||
|
|
||||||
// Set properties not already set in the constructor
|
// Set properties not already set in the constructor
|
||||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||||
|
|
||||||
|
// we skip the id property since it was already set
|
||||||
|
if (idProperty != null && idProperty.equals(prop)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object obj = getValueInternal(prop, dbo, evaluator, result);
|
accessor.setProperty(prop, getValueInternal(prop, dbo, evaluator, currentPath));
|
||||||
wrapper.setProperty(prop, obj);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,19 +286,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
||||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||||
|
|
||||||
MongoPersistentProperty property = association.getInverse();
|
final MongoPersistentProperty property = association.getInverse();
|
||||||
|
Object value = dbo.get(property.getFieldName());
|
||||||
|
|
||||||
Object value = dbo.get(property.getName());
|
if (value == null) {
|
||||||
DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
|
return;
|
||||||
Object obj = dbRefResolver.resolveDbRef(property, dbref, new DbRefResolverCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resolve(MongoPersistentProperty property) {
|
|
||||||
return getValueInternal(property, dbo, evaluator, parent);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.setProperty(property, obj);
|
DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
|
||||||
|
|
||||||
|
DbRefProxyHandler handler = new DefaultDbRefProxyHandler(spELContext, mappingContext,
|
||||||
|
MappingMongoConverter.this);
|
||||||
|
DbRefResolverCallback callback = new DefaultDbRefResolverCallback(dbo, currentPath, evaluator,
|
||||||
|
MappingMongoConverter.this);
|
||||||
|
|
||||||
|
accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -294,6 +320,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
Assert.isTrue(annotation != null, "The referenced property has to be mapped with @DBRef!");
|
Assert.isTrue(annotation != null, "The referenced property has to be mapped with @DBRef!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @see DATAMONGO-913
|
||||||
|
if (object instanceof LazyLoadingProxy) {
|
||||||
|
return ((LazyLoadingProxy) object).toDBRef();
|
||||||
|
}
|
||||||
|
|
||||||
return createDBRef(object, referingProperty);
|
return createDBRef(object, referingProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,14 +340,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean handledByCustomConverter = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class) != null;
|
Class<?> entityType = obj.getClass();
|
||||||
TypeInformation<? extends Object> type = ClassTypeInformation.from(obj.getClass());
|
boolean handledByCustomConverter = conversions.getCustomWriteTarget(entityType, DBObject.class) != null;
|
||||||
|
TypeInformation<? extends Object> type = ClassTypeInformation.from(entityType);
|
||||||
|
|
||||||
if (!handledByCustomConverter && !(dbo instanceof BasicDBList)) {
|
if (!handledByCustomConverter && !(dbo instanceof BasicDBList)) {
|
||||||
typeMapper.writeType(type, dbo);
|
typeMapper.writeType(type, dbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeInternal(obj, dbo, type);
|
Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj;
|
||||||
|
|
||||||
|
writeInternal(target, dbo, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,7 +366,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> customTarget = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class);
|
Class<?> entityType = obj.getClass();
|
||||||
|
Class<?> customTarget = conversions.getCustomWriteTarget(entityType, DBObject.class);
|
||||||
|
|
||||||
if (customTarget != null) {
|
if (customTarget != null) {
|
||||||
DBObject result = conversionService.convert(obj, DBObject.class);
|
DBObject result = conversionService.convert(obj, DBObject.class);
|
||||||
@@ -340,17 +375,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Map.class.isAssignableFrom(obj.getClass())) {
|
if (Map.class.isAssignableFrom(entityType)) {
|
||||||
writeMapInternal((Map<Object, Object>) obj, dbo, ClassTypeInformation.MAP);
|
writeMapInternal((Map<Object, Object>) obj, dbo, ClassTypeInformation.MAP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Collection.class.isAssignableFrom(obj.getClass())) {
|
if (Collection.class.isAssignableFrom(entityType)) {
|
||||||
writeCollectionInternal((Collection<?>) obj, ClassTypeInformation.LIST, (BasicDBList) dbo);
|
writeCollectionInternal((Collection<?>) obj, ClassTypeInformation.LIST, (BasicDBList) dbo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(obj.getClass());
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
|
||||||
writeInternal(obj, dbo, entity);
|
writeInternal(obj, dbo, entity);
|
||||||
addCustomTypeKeyIfNecessary(typeHint, obj, dbo);
|
addCustomTypeKeyIfNecessary(typeHint, obj, dbo);
|
||||||
}
|
}
|
||||||
@@ -365,13 +400,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName());
|
throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
final BeanWrapper<Object> wrapper = BeanWrapper.create(obj, conversionService);
|
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(obj);
|
||||||
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||||
|
|
||||||
if (!dbo.containsField("_id") && null != idProperty) {
|
if (!dbo.containsField("_id") && null != idProperty) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object id = wrapper.getProperty(idProperty, Object.class);
|
Object id = accessor.getProperty(idProperty);
|
||||||
dbo.put("_id", idMapper.convertId(id));
|
dbo.put("_id", idMapper.convertId(id));
|
||||||
} catch (ConversionException ignored) {}
|
} catch (ConversionException ignored) {}
|
||||||
}
|
}
|
||||||
@@ -380,11 +415,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||||
|
|
||||||
if (prop.equals(idProperty)) {
|
if (prop.equals(idProperty) || !prop.isWritable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object propertyObj = wrapper.getProperty(prop);
|
Object propertyObj = accessor.getProperty(prop);
|
||||||
|
|
||||||
if (null != propertyObj) {
|
if (null != propertyObj) {
|
||||||
|
|
||||||
@@ -398,10 +433,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
});
|
});
|
||||||
|
|
||||||
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
||||||
|
|
||||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||||
|
|
||||||
MongoPersistentProperty inverseProp = association.getInverse();
|
MongoPersistentProperty inverseProp = association.getInverse();
|
||||||
Class<?> type = inverseProp.getType();
|
Object propertyObj = accessor.getProperty(inverseProp);
|
||||||
Object propertyObj = wrapper.getProperty(inverseProp, type);
|
|
||||||
if (null != propertyObj) {
|
if (null != propertyObj) {
|
||||||
writePropertyInternal(propertyObj, dbo, inverseProp);
|
writePropertyInternal(propertyObj, dbo, inverseProp);
|
||||||
}
|
}
|
||||||
@@ -457,7 +494,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* If we have a LazyLoadingProxy we make sure it is initialized first.
|
* If we have a LazyLoadingProxy we make sure it is initialized first.
|
||||||
*/
|
*/
|
||||||
if (obj instanceof LazyLoadingProxy) {
|
if (obj instanceof LazyLoadingProxy) {
|
||||||
obj = ((LazyLoadingProxy) obj).initialize();
|
obj = ((LazyLoadingProxy) obj).getTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup potential custom target type
|
// Lookup potential custom target type
|
||||||
@@ -471,7 +508,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
Object existingValue = accessor.get(prop);
|
Object existingValue = accessor.get(prop);
|
||||||
BasicDBObject propDbObj = existingValue instanceof BasicDBObject ? (BasicDBObject) existingValue
|
BasicDBObject propDbObj = existingValue instanceof BasicDBObject ? (BasicDBObject) existingValue
|
||||||
: new BasicDBObject();
|
: new BasicDBObject();
|
||||||
addCustomTypeKeyIfNecessary(type, obj, propDbObj);
|
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, propDbObj);
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass()) ? mappingContext
|
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass()) ? mappingContext
|
||||||
.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
|
.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
|
||||||
@@ -554,7 +591,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
|
|
||||||
if (conversions.isSimpleType(key.getClass())) {
|
if (conversions.isSimpleType(key.getClass())) {
|
||||||
|
|
||||||
String simpleKey = potentiallyEscapeMapKey(key.toString());
|
String simpleKey = prepareMapKey(key.toString());
|
||||||
dbObject.put(simpleKey, value != null ? createDBRef(value, property) : null);
|
dbObject.put(simpleKey, value != null ? createDBRef(value, property) : null);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -606,12 +643,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeInformation<?> propertyType) {
|
protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeInformation<?> propertyType) {
|
||||||
|
|
||||||
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
|
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
|
||||||
|
|
||||||
Object key = entry.getKey();
|
Object key = entry.getKey();
|
||||||
Object val = entry.getValue();
|
Object val = entry.getValue();
|
||||||
|
|
||||||
if (conversions.isSimpleType(key.getClass())) {
|
if (conversions.isSimpleType(key.getClass())) {
|
||||||
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
|
|
||||||
// being convertable
|
String simpleKey = prepareMapKey(key);
|
||||||
String simpleKey = potentiallyEscapeMapKey(key.toString());
|
|
||||||
if (val == null || conversions.isSimpleType(val.getClass())) {
|
if (val == null || conversions.isSimpleType(val.getClass())) {
|
||||||
writeSimpleInternal(val, dbo, simpleKey);
|
writeSimpleInternal(val, dbo, simpleKey);
|
||||||
} else if (val instanceof Collection || val.getClass().isArray()) {
|
} else if (val instanceof Collection || val.getClass().isArray()) {
|
||||||
@@ -632,6 +670,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the given {@link Map} key to be converted into a {@link String}. Will invoke potentially registered custom
|
||||||
|
* conversions and escape dots from the result as they're not supported as {@link Map} key in MongoDB.
|
||||||
|
*
|
||||||
|
* @param key must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String prepareMapKey(Object key) {
|
||||||
|
|
||||||
|
Assert.notNull(key, "Map key must not be null!");
|
||||||
|
|
||||||
|
String convertedKey = potentiallyConvertMapKey(key);
|
||||||
|
return potentiallyEscapeMapKey(convertedKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
|
* Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
|
||||||
* conversion if none is configured.
|
* conversion if none is configured.
|
||||||
@@ -654,6 +707,22 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return source.replaceAll("\\.", mapKeyDotReplacement);
|
return source.replaceAll("\\.", mapKeyDotReplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link String} representation of the given {@link Map} key
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String potentiallyConvertMapKey(Object key) {
|
||||||
|
|
||||||
|
if (key instanceof String) {
|
||||||
|
return (String) key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversions.hasCustomWriteTarget(key.getClass(), String.class) ? (String) getPotentiallyConvertedSimpleWrite(key)
|
||||||
|
: key.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the map key replacements in the given key just read with a dot in case a map key replacement has been
|
* Translates the map key replacements in the given key just read with a dot in case a map key replacement has been
|
||||||
* configured.
|
* configured.
|
||||||
@@ -677,10 +746,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
|
|
||||||
TypeInformation<?> actualType = type != null ? type.getActualType() : null;
|
TypeInformation<?> actualType = type != null ? type.getActualType() : null;
|
||||||
Class<?> reference = actualType == null ? Object.class : actualType.getType();
|
Class<?> reference = actualType == null ? Object.class : actualType.getType();
|
||||||
|
Class<?> valueType = ClassUtils.getUserClass(value.getClass());
|
||||||
|
|
||||||
boolean notTheSameClass = !value.getClass().equals(reference);
|
boolean notTheSameClass = !valueType.equals(reference);
|
||||||
if (notTheSameClass) {
|
if (notTheSameClass) {
|
||||||
typeMapper.writeType(value.getClass(), dbObject);
|
typeMapper.writeType(valueType, dbObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,7 +803,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
|
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
|
||||||
|
|
||||||
if (value == null || target == null) {
|
if (value == null || target == null || target.isAssignableFrom(value.getClass())) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +815,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return Enum.valueOf((Class<Enum>) target, value.toString());
|
return Enum.valueOf((Class<Enum>) target, value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return target.isAssignableFrom(value.getClass()) ? value : conversionService.convert(value, target);
|
return conversionService.convert(value, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
|
protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
|
||||||
@@ -774,8 +844,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
if (target.getClass().equals(idProperty.getType())) {
|
if (target.getClass().equals(idProperty.getType())) {
|
||||||
id = target;
|
id = target;
|
||||||
} else {
|
} else {
|
||||||
BeanWrapper<Object> wrapper = BeanWrapper.create(target, conversionService);
|
PersistentPropertyAccessor accessor = targetEntity.getPropertyAccessor(target);
|
||||||
id = wrapper.getProperty(idProperty, Object.class);
|
id = accessor.getProperty(idProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null == id) {
|
if (null == id) {
|
||||||
@@ -786,11 +856,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
idMapper.convertId(id));
|
idMapper.convertId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator eval,
|
/*
|
||||||
Object parent) {
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.ValueResolver#getValueInternal(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, com.mongodb.DBObject, org.springframework.data.mapping.model.SpELExpressionEvaluator, java.lang.Object)
|
||||||
MongoDbPropertyValueProvider provider = new MongoDbPropertyValueProvider(dbo, spELContext, parent);
|
*/
|
||||||
return provider.getPropertyValue(prop);
|
@Override
|
||||||
|
public Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||||
|
ObjectPath path) {
|
||||||
|
return new MongoDbPropertyValueProvider(dbo, evaluator, path).getPropertyValue(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -798,11 +871,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
*
|
*
|
||||||
* @param targetType must not be {@literal null}.
|
* @param targetType must not be {@literal null}.
|
||||||
* @param sourceValue must not be {@literal null}.
|
* @param sourceValue must not be {@literal null}.
|
||||||
|
* @param path must not be {@literal null}.
|
||||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||||
*/
|
*/
|
||||||
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, Object parent) {
|
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, ObjectPath path) {
|
||||||
|
|
||||||
Assert.notNull(targetType);
|
Assert.notNull(targetType, "Target type must not be null!");
|
||||||
|
Assert.notNull(path, "Object path must not be null!");
|
||||||
|
|
||||||
Class<?> collectionType = targetType.getType();
|
Class<?> collectionType = targetType.getType();
|
||||||
|
|
||||||
@@ -823,9 +898,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
|
|
||||||
if (dbObjItem instanceof DBRef) {
|
if (dbObjItem instanceof DBRef) {
|
||||||
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem),
|
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem),
|
||||||
parent));
|
path));
|
||||||
} else if (dbObjItem instanceof DBObject) {
|
} else if (dbObjItem instanceof DBObject) {
|
||||||
items.add(read(componentType, (DBObject) dbObjItem, parent));
|
items.add(read(componentType, (DBObject) dbObjItem, path));
|
||||||
} else {
|
} else {
|
||||||
items.add(getPotentiallyConvertedSimpleRead(dbObjItem, rawComponentType));
|
items.add(getPotentiallyConvertedSimpleRead(dbObjItem, rawComponentType));
|
||||||
}
|
}
|
||||||
@@ -838,13 +913,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* Reads the given {@link DBObject} into a {@link Map}. will recursively resolve nested {@link Map}s as well.
|
* Reads the given {@link DBObject} into a {@link Map}. will recursively resolve nested {@link Map}s as well.
|
||||||
*
|
*
|
||||||
* @param type the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link DBObject}.
|
* @param type the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link DBObject}.
|
||||||
* @param dbObject
|
* @param dbObject must not be {@literal null}
|
||||||
|
* @param path must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject, Object parent) {
|
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject, ObjectPath path) {
|
||||||
|
|
||||||
Assert.notNull(dbObject);
|
Assert.notNull(dbObject, "DBObject must not be null!");
|
||||||
|
Assert.notNull(path, "Object path must not be null!");
|
||||||
|
|
||||||
Class<?> mapType = typeMapper.readType(dbObject, type).getType();
|
Class<?> mapType = typeMapper.readType(dbObject, type).getType();
|
||||||
|
|
||||||
@@ -871,7 +948,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
Object value = entry.getValue();
|
Object value = entry.getValue();
|
||||||
|
|
||||||
if (value instanceof DBObject) {
|
if (value instanceof DBObject) {
|
||||||
map.put(key, read(valueType, (DBObject) value, parent));
|
map.put(key, read(valueType, (DBObject) value, path));
|
||||||
} else if (value instanceof DBRef) {
|
} else if (value instanceof DBRef) {
|
||||||
map.put(key, DBRef.class.equals(rawValueType) ? value : read(valueType, readRef((DBRef) value)));
|
map.put(key, DBRef.class.equals(rawValueType) ? value : read(valueType, readRef((DBRef) value)));
|
||||||
} else {
|
} else {
|
||||||
@@ -883,21 +960,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> List<?> unwrapList(BasicDBList dbList, TypeInformation<T> targetType) {
|
|
||||||
List<Object> rootList = new ArrayList<Object>();
|
|
||||||
for (int i = 0; i < dbList.size(); i++) {
|
|
||||||
Object obj = dbList.get(i);
|
|
||||||
if (obj instanceof BasicDBList) {
|
|
||||||
rootList.add(unwrapList((BasicDBList) obj, targetType.getComponentType()));
|
|
||||||
} else if (obj instanceof DBObject) {
|
|
||||||
rootList.add(read(targetType, (DBObject) obj));
|
|
||||||
} else {
|
|
||||||
rootList.add(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rootList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object, org.springframework.data.util.TypeInformation)
|
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object, org.springframework.data.util.TypeInformation)
|
||||||
@@ -919,7 +981,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return getPotentiallyConvertedSimpleWrite(obj);
|
return getPotentiallyConvertedSimpleWrite(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeInformation<?> typeHint = typeInformation == null ? null : ClassTypeInformation.OBJECT;
|
TypeInformation<?> typeHint = typeInformation;
|
||||||
|
|
||||||
if (obj instanceof BasicDBList) {
|
if (obj instanceof BasicDBList) {
|
||||||
return maybeConvertList((BasicDBList) obj, typeHint);
|
return maybeConvertList((BasicDBList) obj, typeHint);
|
||||||
@@ -1007,24 +1069,34 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return dbObject;
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link PropertyValueProvider} to evaluate a SpEL expression if present on the property or simply accesses the field
|
||||||
|
* of the configured source {@link DBObject}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
private class MongoDbPropertyValueProvider implements PropertyValueProvider<MongoPersistentProperty> {
|
private class MongoDbPropertyValueProvider implements PropertyValueProvider<MongoPersistentProperty> {
|
||||||
|
|
||||||
private final DBObjectAccessor source;
|
private final DBObjectAccessor source;
|
||||||
private final SpELExpressionEvaluator evaluator;
|
private final SpELExpressionEvaluator evaluator;
|
||||||
private final Object parent;
|
private final ObjectPath path;
|
||||||
|
|
||||||
public MongoDbPropertyValueProvider(DBObject source, SpELContext factory, Object parent) {
|
/**
|
||||||
this(source, new DefaultSpELExpressionEvaluator(source, factory), parent);
|
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
|
||||||
}
|
* {@link ObjectPath}.
|
||||||
|
*
|
||||||
public MongoDbPropertyValueProvider(DBObject source, DefaultSpELExpressionEvaluator evaluator, Object parent) {
|
* @param source must not be {@literal null}.
|
||||||
|
* @param evaluator must not be {@literal null}.
|
||||||
|
* @param path can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MongoDbPropertyValueProvider(DBObject source, SpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||||
|
|
||||||
Assert.notNull(source);
|
Assert.notNull(source);
|
||||||
Assert.notNull(evaluator);
|
Assert.notNull(evaluator);
|
||||||
|
|
||||||
this.source = new DBObjectAccessor(source);
|
this.source = new DBObjectAccessor(source);
|
||||||
this.evaluator = evaluator;
|
this.evaluator = evaluator;
|
||||||
this.parent = parent;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1040,7 +1112,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return readValue(value, property.getTypeInformation(), parent);
|
return readValue(value, property.getTypeInformation(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,7 +1125,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
private class ConverterAwareSpELExpressionParameterValueProvider extends
|
private class ConverterAwareSpELExpressionParameterValueProvider extends
|
||||||
SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
||||||
|
|
||||||
private final Object parent;
|
private final ObjectPath path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
|
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
|
||||||
@@ -1063,10 +1135,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* @param delegate must not be {@literal null}.
|
* @param delegate must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator,
|
public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator,
|
||||||
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate, Object parent) {
|
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate, ObjectPath path) {
|
||||||
|
|
||||||
super(evaluator, conversionService, delegate);
|
super(evaluator, conversionService, delegate);
|
||||||
this.parent = parent;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1075,28 +1147,44 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
|
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
|
||||||
return readValue(object, parameter.getType(), parent);
|
return readValue(object, parameter.getType(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T> T readValue(Object value, TypeInformation<?> type, Object parent) {
|
private <T> T readValue(Object value, TypeInformation<?> type, ObjectPath path) {
|
||||||
|
|
||||||
Class<?> rawType = type.getType();
|
Class<?> rawType = type.getType();
|
||||||
|
|
||||||
if (conversions.hasCustomReadTarget(value.getClass(), rawType)) {
|
if (conversions.hasCustomReadTarget(value.getClass(), rawType)) {
|
||||||
return (T) conversionService.convert(value, rawType);
|
return (T) conversionService.convert(value, rawType);
|
||||||
} else if (value instanceof DBRef) {
|
} else if (value instanceof DBRef) {
|
||||||
return (T) (rawType.equals(DBRef.class) ? value : read(type, readRef((DBRef) value), parent));
|
return potentiallyReadOrResolveDbRef((DBRef) value, type, path, rawType);
|
||||||
} else if (value instanceof BasicDBList) {
|
} else if (value instanceof BasicDBList) {
|
||||||
return (T) readCollectionOrArray(type, (BasicDBList) value, parent);
|
return (T) readCollectionOrArray(type, (BasicDBList) value, path);
|
||||||
} else if (value instanceof DBObject) {
|
} else if (value instanceof DBObject) {
|
||||||
return (T) read(type, (DBObject) value, parent);
|
return (T) read(type, (DBObject) value, path);
|
||||||
} else {
|
} else {
|
||||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T potentiallyReadOrResolveDbRef(DBRef dbref, TypeInformation<?> type, ObjectPath path, Class<?> rawType) {
|
||||||
|
|
||||||
|
if (rawType.equals(DBRef.class)) {
|
||||||
|
return (T) dbref;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getCollectionName());
|
||||||
|
|
||||||
|
if (object != null) {
|
||||||
|
return (T) object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) (object != null ? object : read(type, readRef(dbref), path));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the fetch operation for the given {@link DBRef}.
|
* Performs the fetch operation for the given {@link DBRef}.
|
||||||
*
|
*
|
||||||
@@ -1104,6 +1192,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
DBObject readRef(DBRef ref) {
|
DBObject readRef(DBRef ref) {
|
||||||
return ref.fetch();
|
return dbRefResolver.fetch(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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,13 +20,19 @@ import java.math.BigInteger;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.bson.types.Code;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.springframework.core.convert.ConversionFailedException;
|
import org.springframework.core.convert.ConversionFailedException;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.convert.ReadingConverter;
|
import org.springframework.data.convert.ReadingConverter;
|
||||||
|
import org.springframework.data.convert.WritingConverter;
|
||||||
|
import org.springframework.data.mongodb.core.query.Term;
|
||||||
|
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.BasicDBObjectBuilder;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,6 +40,7 @@ import com.mongodb.DBObject;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
abstract class MongoConverters {
|
abstract class MongoConverters {
|
||||||
|
|
||||||
@@ -160,4 +167,65 @@ abstract class MongoConverters {
|
|||||||
return source == null ? null : source.toString();
|
return source == null ? null : source.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
@WritingConverter
|
||||||
|
public static enum TermToStringConverter implements Converter<Term, String> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(Term source) {
|
||||||
|
return source == null ? null : source.getFormatted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public static enum DBObjectToNamedMongoScriptCoverter implements Converter<DBObject, NamedMongoScript> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NamedMongoScript convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = source.get("_id").toString();
|
||||||
|
Object rawValue = source.get("value");
|
||||||
|
|
||||||
|
return new NamedMongoScript(id, ((Code) rawValue).getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public static enum NamedMongoScriptToDBObjectConverter implements Converter<NamedMongoScript, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DBObject convert(NamedMongoScript source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return new BasicDBObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicDBObjectBuilder builder = new BasicDBObjectBuilder();
|
||||||
|
|
||||||
|
builder.append("_id", source.getName());
|
||||||
|
builder.append("value", new Code(source.getCode()));
|
||||||
|
|
||||||
|
return builder.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.convert;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A path of objects nested into each other. The type allows access to all parent objects currently in creation even
|
||||||
|
* when resolving more nested objects. This allows to avoid re-resolving object instances that are logically equivalent
|
||||||
|
* to already resolved ones.
|
||||||
|
* <p>
|
||||||
|
* An immutable ordered set of target objects for {@link DBObject} to {@link Object} conversions. Object paths can be
|
||||||
|
* constructed by the {@link #toObjectPath(Object)} method and extended via {@link #push(Object)}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
class ObjectPath {
|
||||||
|
|
||||||
|
public static final ObjectPath ROOT = new ObjectPath();
|
||||||
|
|
||||||
|
private final List<ObjectPathItem> items;
|
||||||
|
|
||||||
|
private ObjectPath() {
|
||||||
|
this.items = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ObjectPath} from the given parent {@link ObjectPath} by adding the provided
|
||||||
|
* {@link ObjectPathItem} to it.
|
||||||
|
*
|
||||||
|
* @param parent can be {@literal null}.
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
private ObjectPath(ObjectPath parent, ObjectPath.ObjectPathItem item) {
|
||||||
|
|
||||||
|
List<ObjectPath.ObjectPathItem> items = new ArrayList<ObjectPath.ObjectPathItem>(parent.items);
|
||||||
|
items.add(item);
|
||||||
|
|
||||||
|
this.items = Collections.unmodifiableList(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of the {@link ObjectPath} with the given {@link Object} as current object.
|
||||||
|
*
|
||||||
|
* @param object must not be {@literal null}.
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ObjectPath push(Object object, MongoPersistentEntity<?> entity, Object id) {
|
||||||
|
|
||||||
|
Assert.notNull(object, "Object must not be null!");
|
||||||
|
Assert.notNull(entity, "MongoPersistentEntity must not be null!");
|
||||||
|
|
||||||
|
ObjectPathItem item = new ObjectPathItem(object, id, entity.getCollection());
|
||||||
|
return new ObjectPath(this, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the object with the given id and stored in the given collection if it's contained in the {@link ObjectPath}
|
||||||
|
* .
|
||||||
|
*
|
||||||
|
* @param id must not be {@literal null}.
|
||||||
|
* @param collection must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getPathItem(Object id, String collection) {
|
||||||
|
|
||||||
|
Assert.notNull(id, "Id must not be null!");
|
||||||
|
Assert.hasText(collection, "Collection name must not be null!");
|
||||||
|
|
||||||
|
for (ObjectPathItem item : items) {
|
||||||
|
|
||||||
|
Object object = item.getObject();
|
||||||
|
|
||||||
|
if (object == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getIdValue() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.equals(item.getCollection()) && id.equals(item.getIdValue())) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current object of the {@link ObjectPath} or {@literal null} if the path is empty.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getCurrentObject() {
|
||||||
|
return items.isEmpty() ? null : items.get(items.size() - 1).getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
return "[empty]";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> strings = new ArrayList<String>(items.size());
|
||||||
|
|
||||||
|
for (ObjectPathItem item : items) {
|
||||||
|
strings.add(item.object.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringUtils.collectionToDelimitedString(strings, " -> ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item in an {@link ObjectPath}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class ObjectPathItem {
|
||||||
|
|
||||||
|
private final Object object;
|
||||||
|
private final Object idValue;
|
||||||
|
private final String collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ObjectPathItem}.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @param idValue
|
||||||
|
* @param collection
|
||||||
|
*/
|
||||||
|
ObjectPathItem(Object object, Object idValue, String collection) {
|
||||||
|
|
||||||
|
this.object = object;
|
||||||
|
this.idValue = idValue;
|
||||||
|
this.collection = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObject() {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getIdValue() {
|
||||||
|
return idValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCollection() {
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2014 the original author or authors.
|
* Copyright 2011-2015 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.
|
||||||
@@ -57,6 +57,11 @@ import com.mongodb.DBRef;
|
|||||||
public class QueryMapper {
|
public class QueryMapper {
|
||||||
|
|
||||||
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
|
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
|
||||||
|
private static final DBObject META_TEXT_SCORE = new BasicDBObject("$meta", "textScore");
|
||||||
|
|
||||||
|
private enum MetaMapping {
|
||||||
|
FORCE, WHEN_PRESENT, IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
private final MongoConverter converter;
|
private final MongoConverter converter;
|
||||||
@@ -119,6 +124,61 @@ public class QueryMapper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps fields used for sorting to the {@link MongoPersistentEntity}s properties. <br />
|
||||||
|
* Also converts properties to their {@code $meta} representation if present.
|
||||||
|
*
|
||||||
|
* @param sortObject
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public DBObject getMappedSort(DBObject sortObject, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
|
if (sortObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject mappedSort = getMappedObject(sortObject, entity);
|
||||||
|
mapMetaAttributes(mappedSort, entity, MetaMapping.WHEN_PRESENT);
|
||||||
|
return mappedSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps fields to retrieve to the {@link MongoPersistentEntity}s properties. <br />
|
||||||
|
* Also onverts and potentially adds missing property {@code $meta} representation.
|
||||||
|
*
|
||||||
|
* @param fieldsObject
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public DBObject getMappedFields(DBObject fieldsObject, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
|
DBObject mappedFields = fieldsObject != null ? getMappedObject(fieldsObject, entity) : new BasicDBObject();
|
||||||
|
mapMetaAttributes(mappedFields, entity, MetaMapping.FORCE);
|
||||||
|
return mappedFields.keySet().isEmpty() ? null : mappedFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mapMetaAttributes(DBObject source, MongoPersistentEntity<?> entity, MetaMapping metaMapping) {
|
||||||
|
|
||||||
|
if (entity == null || source == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.hasTextScoreProperty() && !MetaMapping.IGNORE.equals(metaMapping)) {
|
||||||
|
MongoPersistentProperty textScoreProperty = entity.getTextScoreProperty();
|
||||||
|
if (MetaMapping.FORCE.equals(metaMapping)
|
||||||
|
|| (MetaMapping.WHEN_PRESENT.equals(metaMapping) && source.containsField(textScoreProperty.getFieldName()))) {
|
||||||
|
source.putAll(getMappedTextScoreField(textScoreProperty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DBObject getMappedTextScoreField(MongoPersistentProperty property) {
|
||||||
|
return new BasicDBObject(property.getFieldName(), META_TEXT_SCORE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the mapped object value for given field out of rawValue taking nested {@link Keyword}s into account
|
* Extracts the mapped object value for given field out of rawValue taking nested {@link Keyword}s into account
|
||||||
*
|
*
|
||||||
@@ -250,14 +310,32 @@ public class QueryMapper {
|
|||||||
* type of the given value is compatible with the type of the given document field in order to deal with potential
|
* type of the given value is compatible with the type of the given document field in order to deal with potential
|
||||||
* query field exclusions, since MongoDB uses the {@code int} {@literal 0} as an indicator for an excluded field.
|
* query field exclusions, since MongoDB uses the {@code int} {@literal 0} as an indicator for an excluded field.
|
||||||
*
|
*
|
||||||
* @param documentField
|
* @param documentField must not be {@literal null}.
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected boolean isAssociationConversionNecessary(Field documentField, Object value) {
|
protected boolean isAssociationConversionNecessary(Field documentField, Object value) {
|
||||||
return documentField.isAssociation() && value != null
|
|
||||||
&& (documentField.getProperty().getActualType().isAssignableFrom(value.getClass()) //
|
Assert.notNull(documentField, "Document field must not be null!");
|
||||||
|| documentField.getPropertyEntity().getIdProperty().getActualType().isAssignableFrom(value.getClass()));
|
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!documentField.isAssociation()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<? extends Object> type = value.getClass();
|
||||||
|
MongoPersistentProperty property = documentField.getProperty();
|
||||||
|
|
||||||
|
if (property.getActualType().isAssignableFrom(type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoPersistentEntity<?> entity = documentField.getPropertyEntity();
|
||||||
|
return entity.hasIdProperty()
|
||||||
|
&& (type.equals(DBRef.class) || entity.getIdProperty().getActualType().isAssignableFrom(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,7 +367,7 @@ public class QueryMapper {
|
|||||||
* @return the converted mongo type or null if source is null
|
* @return the converted mongo type or null if source is null
|
||||||
*/
|
*/
|
||||||
protected Object delegateConvertToMongoType(Object source, MongoPersistentEntity<?> entity) {
|
protected Object delegateConvertToMongoType(Object source, MongoPersistentEntity<?> entity) {
|
||||||
return converter.convertToMongoType(source);
|
return converter.convertToMongoType(source, entity == null ? null : entity.getTypeInformation());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object convertAssociation(Object source, Field field) {
|
protected Object convertAssociation(Object source, Field field) {
|
||||||
@@ -305,10 +383,16 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
protected Object convertAssociation(Object source, MongoPersistentProperty property) {
|
protected Object convertAssociation(Object source, MongoPersistentProperty property) {
|
||||||
|
|
||||||
if (property == null || source == null || source instanceof DBRef || source instanceof DBObject) {
|
if (property == null || source == null || source instanceof DBObject) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source instanceof DBRef) {
|
||||||
|
|
||||||
|
DBRef ref = (DBRef) source;
|
||||||
|
return new DBRef(ref.getCollectionName(), convertId(ref.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
if (source instanceof Iterable) {
|
if (source instanceof Iterable) {
|
||||||
BasicDBList result = new BasicDBList();
|
BasicDBList result = new BasicDBList();
|
||||||
for (Object element : (Iterable<?>) source) {
|
for (Object element : (Iterable<?>) source) {
|
||||||
@@ -380,14 +464,21 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
public Object convertId(Object id) {
|
public Object convertId(Object id) {
|
||||||
|
|
||||||
try {
|
if (id == null) {
|
||||||
return conversionService.convert(id, ObjectId.class);
|
return null;
|
||||||
} catch (ConversionException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id instanceof String) {
|
||||||
|
return ObjectId.isValid(id.toString()) ? conversionService.convert(id, ObjectId.class) : id;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return conversionService.canConvert(id.getClass(), ObjectId.class) ? conversionService
|
||||||
|
.convert(id, ObjectId.class) : delegateConvertToMongoType(id, null);
|
||||||
|
} catch (ConversionException o_O) {
|
||||||
return delegateConvertToMongoType(id, null);
|
return delegateConvertToMongoType(id, null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given {@link Object} is a keyword, i.e. if it's a {@link DBObject} with a keyword key.
|
* Returns whether the given {@link Object} is a keyword, i.e. if it's a {@link DBObject} with a keyword key.
|
||||||
@@ -594,6 +685,21 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
public MetadataBackedField(String name, MongoPersistentEntity<?> entity,
|
public MetadataBackedField(String name, MongoPersistentEntity<?> entity,
|
||||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context) {
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context) {
|
||||||
|
this(name, entity, context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link MetadataBackedField} with the given name, {@link MongoPersistentEntity} and
|
||||||
|
* {@link MappingContext} with the given {@link MongoPersistentProperty}.
|
||||||
|
*
|
||||||
|
* @param name must not be {@literal null} or empty.
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param context must not be {@literal null}.
|
||||||
|
* @param property may be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MetadataBackedField(String name, MongoPersistentEntity<?> entity,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context,
|
||||||
|
MongoPersistentProperty property) {
|
||||||
|
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
@@ -603,7 +709,7 @@ public class QueryMapper {
|
|||||||
this.mappingContext = context;
|
this.mappingContext = context;
|
||||||
|
|
||||||
this.path = getPath(name);
|
this.path = getPath(name);
|
||||||
this.property = path == null ? null : path.getLeafProperty();
|
this.property = path == null ? property : path.getLeafProperty();
|
||||||
this.association = findAssociation();
|
this.association = findAssociation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,7 +719,7 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MetadataBackedField with(String name) {
|
public MetadataBackedField with(String name) {
|
||||||
return new MetadataBackedField(name, entity, mappingContext);
|
return new MetadataBackedField(name, entity, mappingContext, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -693,7 +799,7 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getMappedKey() {
|
public String getMappedKey() {
|
||||||
return path == null ? name : path.toDotPath(getPropertyConverter());
|
return path == null ? name : path.toDotPath(isAssociation() ? getAssociationConverter() : getPropertyConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
|
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
|
||||||
@@ -745,5 +851,56 @@ public class QueryMapper {
|
|||||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||||
return PropertyToFieldNameConverter.INSTANCE;
|
return PropertyToFieldNameConverter.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link Converter} to use for creating the mapped key of an association. Default implementation is
|
||||||
|
* {@link AssociationConverter}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||||
|
return new AssociationConverter(getAssociation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter to skip all properties after an association property was rendered.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
protected static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||||
|
|
||||||
|
private final MongoPersistentProperty property;
|
||||||
|
private boolean associationFound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||||
|
*
|
||||||
|
* @param association must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||||
|
|
||||||
|
Assert.notNull(association, "Association must not be null!");
|
||||||
|
this.property = association.getInverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String convert(MongoPersistentProperty source) {
|
||||||
|
|
||||||
|
if (associationFound) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.equals(source)) {
|
||||||
|
associationFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.getFieldName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.convert;
|
||||||
|
|
||||||
|
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.DBCollection;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReflectiveDBRefResolver} provides reflective access to {@link DBRef} API that is not consistently available
|
||||||
|
* for various driver versions.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
class ReflectiveDBRefResolver {
|
||||||
|
|
||||||
|
private static final Method FETCH_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
FETCH_METHOD = findMethod(DBRef.class, "fetch");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the object referenced from the database either be directly calling {@link DBRef#fetch()} or
|
||||||
|
* {@link DBCollection#findOne(Object)}.
|
||||||
|
*
|
||||||
|
* @param db can be {@literal null} when using MongoDB Java driver in version 2.x.
|
||||||
|
* @param ref must not be {@literal null}.
|
||||||
|
* @return the document that this references.
|
||||||
|
*/
|
||||||
|
public static DBObject fetch(DB db, DBRef ref) {
|
||||||
|
|
||||||
|
Assert.notNull(ref, "DBRef to fetch must not be null!");
|
||||||
|
|
||||||
|
if (isMongo3Driver()) {
|
||||||
|
return db.getCollection(ref.getCollectionName()).findOne(ref.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (DBObject) invokeMethod(FETCH_METHOD, ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
|||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update.Modifier;
|
import org.springframework.data.mongodb.core.query.Update.Modifier;
|
||||||
import org.springframework.data.mongodb.core.query.Update.Modifiers;
|
import org.springframework.data.mongodb.core.query.Update.Modifiers;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
@@ -79,10 +80,19 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
return createMapEntry(field, convertSimpleOrDBObject(rawValue, field.getPropertyEntity()));
|
return createMapEntry(field, convertSimpleOrDBObject(rawValue, field.getPropertyEntity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isUpdateModifier(rawValue)) {
|
if (isQuery(rawValue)) {
|
||||||
|
return createMapEntry(field,
|
||||||
|
super.getMappedObject(((Query) rawValue).getQueryObject(), field.getPropertyEntity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUpdateModifier(rawValue)) {
|
||||||
|
return getMappedUpdateModifier(field, rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
|
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Entry<String, Object> getMappedUpdateModifier(Field field, Object rawValue) {
|
||||||
Object value = null;
|
Object value = null;
|
||||||
|
|
||||||
if (rawValue instanceof Modifier) {
|
if (rawValue instanceof Modifier) {
|
||||||
@@ -99,7 +109,6 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
|
|
||||||
value = modificationOperations;
|
value = modificationOperations;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
throw new IllegalArgumentException(String.format("Unable to map value of type '%s'!", rawValue.getClass()));
|
throw new IllegalArgumentException(String.format("Unable to map value of type '%s'!", rawValue.getClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +128,10 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
return value instanceof Modifier || value instanceof Modifiers;
|
return value instanceof Modifier || value instanceof Modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isQuery(Object value) {
|
||||||
|
return value instanceof Query;
|
||||||
|
}
|
||||||
|
|
||||||
private DBObject getMappedValue(Modifier modifier) {
|
private DBObject getMappedValue(Modifier modifier) {
|
||||||
|
|
||||||
Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT);
|
Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT);
|
||||||
@@ -181,47 +194,48 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||||
return isAssociation() ? new AssociationConverter(getAssociation()) : new UpdatePropertyConverter(key);
|
return new UpdatePropertyConverter(key);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converter to skip all properties after an association property was rendered.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
*/
|
|
||||||
private static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
|
||||||
|
|
||||||
private final MongoPersistentProperty property;
|
|
||||||
private boolean associationFound;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
|
||||||
*
|
|
||||||
* @param association must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
|
||||||
|
|
||||||
Assert.notNull(association, "Association must not be null!");
|
|
||||||
this.property = association.getInverse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getAssociationConverter()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String convert(MongoPersistentProperty source) {
|
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||||
|
return new UpdateAssociationConverter(getAssociation(), key);
|
||||||
if (associationFound) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.equals(source)) {
|
/**
|
||||||
associationFound = true;
|
* Special mapper handling positional parameter {@literal $} within property names.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
private static class UpdateKeyMapper {
|
||||||
|
|
||||||
|
private final Iterator<String> iterator;
|
||||||
|
|
||||||
|
protected UpdateKeyMapper(String rawKey) {
|
||||||
|
|
||||||
|
Assert.hasText(rawKey, "Key must not be null or empty!");
|
||||||
|
|
||||||
|
this.iterator = Arrays.asList(rawKey.split("\\.")).iterator();
|
||||||
|
this.iterator.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
return source.getFieldName();
|
/**
|
||||||
|
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||||
|
*
|
||||||
|
* @param property
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||||
|
|
||||||
|
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||||
|
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -229,10 +243,11 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
* contained in the source update key.
|
* contained in the source update key.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
||||||
|
|
||||||
private final Iterator<String> iterator;
|
private final UpdateKeyMapper mapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
||||||
@@ -243,8 +258,7 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
|
|
||||||
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
||||||
|
|
||||||
this.iterator = Arrays.asList(updateKey.split("\\.")).iterator();
|
this.mapper = new UpdateKeyMapper(updateKey);
|
||||||
this.iterator.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -253,9 +267,37 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String convert(MongoPersistentProperty property) {
|
public String convert(MongoPersistentProperty property) {
|
||||||
|
return mapper.mapPropertyName(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
/**
|
||||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
* {@link Converter} retaining positional parameter {@literal $} for {@link Association}s.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
|
protected static class UpdateAssociationConverter extends AssociationConverter {
|
||||||
|
|
||||||
|
private final UpdateKeyMapper mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||||
|
*
|
||||||
|
* @param association must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
|
||||||
|
|
||||||
|
super(association);
|
||||||
|
this.mapper = new UpdateKeyMapper(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String convert(MongoPersistentProperty source) {
|
||||||
|
return super.convert(source) == null ? null : mapper.mapPropertyName(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal API to trigger the resolution of properties.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
interface ValueResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the value for the given {@link MongoPersistentProperty} within the given {@link DBObject} using the given
|
||||||
|
* {@link SpELExpressionEvaluator} and {@link ObjectPath}.
|
||||||
|
*
|
||||||
|
* @param prop
|
||||||
|
* @param dbo
|
||||||
|
* @param evaluator
|
||||||
|
* @param parent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||||
|
ObjectPath parent);
|
||||||
|
}
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.geo.Point;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a geospatial box value.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Box}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Box extends org.springframework.data.geo.Box implements Shape {
|
|
||||||
|
|
||||||
public static final String COMMAND = "$box";
|
|
||||||
|
|
||||||
public Box(Point lowerLeft, Point upperRight) {
|
|
||||||
super(lowerLeft, upperRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Box(double[] lowerLeft, double[] upperRight) {
|
|
||||||
super(lowerLeft, upperRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
|
||||||
*/
|
|
||||||
public List<? extends Object> asList() {
|
|
||||||
|
|
||||||
List<List<Double>> list = new ArrayList<List<Double>>();
|
|
||||||
|
|
||||||
list.add(Arrays.asList(getFirst().getX(), getFirst().getY()));
|
|
||||||
list.add(Arrays.asList(getSecond().getX(), getSecond().getY()));
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.springframework.data.mongodb.core.geo.Point getLowerLeft() {
|
|
||||||
return new org.springframework.data.mongodb.core.geo.Point(getFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.springframework.data.mongodb.core.geo.Point getUpperRight() {
|
|
||||||
return new org.springframework.data.mongodb.core.geo.Point(getSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
|
||||||
*/
|
|
||||||
public String getCommand() {
|
|
||||||
return COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
|
||||||
import org.springframework.data.geo.Distance;
|
|
||||||
import org.springframework.data.geo.Metrics;
|
|
||||||
import org.springframework.data.geo.Point;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a geospatial circle value.
|
|
||||||
* <p>
|
|
||||||
* Note: We deliberately do not extend org.springframework.data.geo.Circle because introducing it's distance concept
|
|
||||||
* would break the clients that use the old Circle API.
|
|
||||||
*
|
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Circle}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Circle implements Shape {
|
|
||||||
|
|
||||||
public static final String COMMAND = "$center";
|
|
||||||
|
|
||||||
private final Point center;
|
|
||||||
private final double radius;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Circle} from the given {@link Point} and radius.
|
|
||||||
*
|
|
||||||
* @param center must not be {@literal null}.
|
|
||||||
* @param radius must be greater or equal to zero.
|
|
||||||
*/
|
|
||||||
@PersistenceConstructor
|
|
||||||
public Circle(Point center, double radius) {
|
|
||||||
|
|
||||||
Assert.notNull(center);
|
|
||||||
Assert.isTrue(radius >= 0, "Radius must not be negative!");
|
|
||||||
|
|
||||||
this.center = center;
|
|
||||||
this.radius = radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Circle} from the given coordinates and radius as {@link Distance} with a
|
|
||||||
* {@link Metrics#NEUTRAL}.
|
|
||||||
*
|
|
||||||
* @param centerX
|
|
||||||
* @param centerY
|
|
||||||
* @param radius must be greater or equal to zero.
|
|
||||||
*/
|
|
||||||
public Circle(double centerX, double centerY, double radius) {
|
|
||||||
this(new Point(centerX, centerY), radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the center of the {@link Circle}.
|
|
||||||
*
|
|
||||||
* @return will never be {@literal null}.
|
|
||||||
*/
|
|
||||||
public Point getCenter() {
|
|
||||||
return center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the radius of the {@link Circle}.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public double getRadius() {
|
|
||||||
return radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
|
||||||
*/
|
|
||||||
public List<Object> asList() {
|
|
||||||
|
|
||||||
List<Object> result = new ArrayList<Object>();
|
|
||||||
result.add(Arrays.asList(getCenter().getX(), getCenter().getY()));
|
|
||||||
result.add(getRadius());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
|
||||||
*/
|
|
||||||
public String getCommand() {
|
|
||||||
return COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Circle [center=%s, radius=%f]", center, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Circle that = (Circle) obj;
|
|
||||||
|
|
||||||
return this.center.equals(that.center) && this.radius == that.radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = 17;
|
|
||||||
result += 31 * center.hashCode();
|
|
||||||
result += 31 * radius;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value object to create custom {@link Metric}s on the fly.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metric}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class CustomMetric extends org.springframework.data.geo.CustomMetric implements Metric {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a custom {@link Metric} using the given multiplier.
|
|
||||||
*
|
|
||||||
* @param multiplier
|
|
||||||
*/
|
|
||||||
public CustomMetric(double multiplier) {
|
|
||||||
super(multiplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import org.springframework.data.geo.Metric;
|
|
||||||
import org.springframework.data.geo.Metrics;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value object to represent distances in a given metric.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Distance}. This class is scheduled to
|
|
||||||
* be removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Distance extends org.springframework.data.geo.Distance {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Distance}.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public Distance(double value) {
|
|
||||||
this(value, Metrics.NEUTRAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Distance(double value, Metric metric) {
|
|
||||||
super(value, metric);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface definition for structures defined in GeoJSON ({@link http://geojson.org/}) format.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public interface GeoJson<T extends Iterable<?>> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String value representing the type of the {@link GeoJson} object.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
* @see http://geojson.org/geojson-spec.html#geojson-objects
|
||||||
|
*/
|
||||||
|
String getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the coordinates member is always an {@link Iterable}. The structure for the elements within is
|
||||||
|
* determined by {@link #getType()} of geometry.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
* @see http://geojson.org/geojson-spec.html#geometry-objects
|
||||||
|
*/
|
||||||
|
T getCoordinates();
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a {@link GeoJsonGeometryCollection} that consists of a {@link List} of {@link GeoJson} objects.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#geometry-collection
|
||||||
|
*/
|
||||||
|
public class GeoJsonGeometryCollection implements GeoJson<Iterable<GeoJson<?>>> {
|
||||||
|
|
||||||
|
private static final String TYPE = "GeometryCollection";
|
||||||
|
|
||||||
|
private final List<GeoJson<?>> geometries = new ArrayList<GeoJson<?>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonGeometryCollection} for the given {@link GeoJson} instances.
|
||||||
|
*
|
||||||
|
* @param geometries
|
||||||
|
*/
|
||||||
|
public GeoJsonGeometryCollection(List<GeoJson<?>> geometries) {
|
||||||
|
|
||||||
|
Assert.notNull(geometries, "Geometries must not be null!");
|
||||||
|
|
||||||
|
this.geometries.addAll(geometries);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterable<GeoJson<?>> getCoordinates() {
|
||||||
|
return Collections.unmodifiableList(this.geometries);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return ObjectUtils.nullSafeHashCode(this.geometries);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof GeoJsonGeometryCollection)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeoJsonGeometryCollection other = (GeoJsonGeometryCollection) obj;
|
||||||
|
|
||||||
|
return ObjectUtils.nullSafeEquals(this.geometries, other.geometries);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJsonLineString} is defined as list of at least 2 {@link Point}s.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#linestring
|
||||||
|
*/
|
||||||
|
public class GeoJsonLineString extends GeoJsonMultiPoint {
|
||||||
|
|
||||||
|
private static final String TYPE = "LineString";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonLineString} for the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param points must not be {@literal null} and have at least 2 entries.
|
||||||
|
*/
|
||||||
|
public GeoJsonLineString(List<Point> points) {
|
||||||
|
super(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonLineString} for the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param first must not be {@literal null}
|
||||||
|
* @param second must not be {@literal null}
|
||||||
|
* @param others can be {@literal null}
|
||||||
|
*/
|
||||||
|
public GeoJsonLineString(Point first, Point second, Point... others) {
|
||||||
|
super(first, second, others);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJsonMultiLineString} is defined as list of {@link GeoJsonLineString}s.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#multilinestring
|
||||||
|
*/
|
||||||
|
public class GeoJsonMultiLineString implements GeoJson<Iterable<GeoJsonLineString>> {
|
||||||
|
|
||||||
|
private static final String TYPE = "MultiLineString";
|
||||||
|
|
||||||
|
private List<GeoJsonLineString> coordinates = new ArrayList<GeoJsonLineString>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new {@link GeoJsonMultiLineString} for the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param lines must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonMultiLineString(List<Point>... lines) {
|
||||||
|
|
||||||
|
Assert.notEmpty(lines, "Points for MultiLineString must not be null!");
|
||||||
|
|
||||||
|
for (List<Point> line : lines) {
|
||||||
|
this.coordinates.add(new GeoJsonLineString(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new {@link GeoJsonMultiLineString} for the given {@link GeoJsonLineString}s.
|
||||||
|
*
|
||||||
|
* @param lines must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonMultiLineString(List<GeoJsonLineString> lines) {
|
||||||
|
|
||||||
|
Assert.notNull(lines, "Lines for MultiLineString must not be null!");
|
||||||
|
|
||||||
|
this.coordinates.addAll(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterable<GeoJsonLineString> getCoordinates() {
|
||||||
|
return Collections.unmodifiableList(this.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return ObjectUtils.nullSafeHashCode(this.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof GeoJsonMultiLineString)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectUtils.nullSafeEquals(this.coordinates, ((GeoJsonMultiLineString) obj).coordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJsonMultiPoint} is defined as list of {@link Point}s.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#multipoint
|
||||||
|
*/
|
||||||
|
public class GeoJsonMultiPoint implements GeoJson<Iterable<Point>> {
|
||||||
|
|
||||||
|
private static final String TYPE = "MultiPoint";
|
||||||
|
|
||||||
|
private final List<Point> points;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param points points must not be {@literal null} and have at least 2 entries.
|
||||||
|
*/
|
||||||
|
public GeoJsonMultiPoint(List<Point> points) {
|
||||||
|
|
||||||
|
Assert.notNull(points, "Points must not be null.");
|
||||||
|
Assert.isTrue(points.size() >= 2, "Minimum of 2 Points required.");
|
||||||
|
|
||||||
|
this.points = new ArrayList<Point>(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param first must not be {@literal null}.
|
||||||
|
* @param second must not be {@literal null}.
|
||||||
|
* @param others must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonMultiPoint(Point first, Point second, Point... others) {
|
||||||
|
|
||||||
|
Assert.notNull(first, "First point must not be null!");
|
||||||
|
Assert.notNull(second, "Second point must not be null!");
|
||||||
|
Assert.notNull(others, "Additional points must not be null!");
|
||||||
|
|
||||||
|
this.points = new ArrayList<Point>();
|
||||||
|
this.points.add(first);
|
||||||
|
this.points.add(second);
|
||||||
|
this.points.addAll(Arrays.asList(others));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Point> getCoordinates() {
|
||||||
|
return Collections.unmodifiableList(this.points);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return ObjectUtils.nullSafeHashCode(this.points);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof GeoJsonMultiPoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectUtils.nullSafeEquals(this.points, ((GeoJsonMultiPoint) obj).points);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJsonMultiPolygon} is defined as a list of {@link GeoJsonPolygon}s.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class GeoJsonMultiPolygon implements GeoJson<Iterable<GeoJsonPolygon>> {
|
||||||
|
|
||||||
|
private static final String TYPE = "MultiPolygon";
|
||||||
|
|
||||||
|
private List<GeoJsonPolygon> coordinates = new ArrayList<GeoJsonPolygon>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoJsonMultiPolygon} for the given {@link GeoJsonPolygon}s.
|
||||||
|
*
|
||||||
|
* @param polygons must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonMultiPolygon(List<GeoJsonPolygon> polygons) {
|
||||||
|
|
||||||
|
Assert.notNull(polygons, "Polygons for MultiPolygon must not be null!");
|
||||||
|
|
||||||
|
this.coordinates.addAll(polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<GeoJsonPolygon> getCoordinates() {
|
||||||
|
return Collections.unmodifiableList(this.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return ObjectUtils.nullSafeHashCode(this.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof GeoJsonMultiPolygon)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectUtils.nullSafeEquals(this.coordinates, ((GeoJsonMultiPolygon) obj).coordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJson} representation of {@link Point}.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#point
|
||||||
|
*/
|
||||||
|
public class GeoJsonPoint extends Point implements GeoJson<List<Double>> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8026303425147474002L;
|
||||||
|
|
||||||
|
private static final String TYPE = "Point";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link GeoJsonPoint} for given coordinates.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
*/
|
||||||
|
public GeoJsonPoint(double x, double y) {
|
||||||
|
super(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link GeoJsonPoint} for given {@link Point}.
|
||||||
|
*
|
||||||
|
* @param point must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonPoint(Point point) {
|
||||||
|
super(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Double> getCoordinates() {
|
||||||
|
return Arrays.asList(Double.valueOf(getX()), Double.valueOf(getY()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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
|
||||||
|
*
|
||||||
|
* http://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.geo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.geo.Polygon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GeoJson} representation of {@link Polygon}. Unlike {@link Polygon} the {@link GeoJsonPolygon} requires a
|
||||||
|
* closed border. Which means that the first and last {@link Point} have to have same coordinate pairs.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.7
|
||||||
|
* @see http://geojson.org/geojson-spec.html#polygon
|
||||||
|
*/
|
||||||
|
public class GeoJsonPolygon extends Polygon implements GeoJson<List<GeoJsonLineString>> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3936163018187247185L;
|
||||||
|
private static final String TYPE = "Polygon";
|
||||||
|
|
||||||
|
private List<GeoJsonLineString> coordinates = new ArrayList<GeoJsonLineString>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new {@link GeoJsonPolygon} from the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param first must not be {@literal null}.
|
||||||
|
* @param second must not be {@literal null}.
|
||||||
|
* @param third must not be {@literal null}.
|
||||||
|
* @param fourth must not be {@literal null}.
|
||||||
|
* @param others can be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonPolygon(Point first, Point second, Point third, Point fourth, final Point... others) {
|
||||||
|
this(asList(first, second, third, fourth, others));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new {@link GeoJsonPolygon} from the given {@link Point}s.
|
||||||
|
*
|
||||||
|
* @param points must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoJsonPolygon(List<Point> points) {
|
||||||
|
|
||||||
|
super(points);
|
||||||
|
this.coordinates.add(new GeoJsonLineString(points));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<GeoJsonLineString> getCoordinates() {
|
||||||
|
return Collections.unmodifiableList(this.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Point> asList(Point first, Point second, Point third, Point fourth, final Point... others) {
|
||||||
|
|
||||||
|
ArrayList<Point> result = new ArrayList<Point>(3 + others.length);
|
||||||
|
|
||||||
|
result.add(first);
|
||||||
|
result.add(second);
|
||||||
|
result.add(third);
|
||||||
|
result.add(fourth);
|
||||||
|
result.addAll(Arrays.asList(others));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom {@link Page} to carry the average distance retrieved from the {@link GeoResults} the {@link GeoPage} is set up
|
|
||||||
* from.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoPage}. This class is scheduled to
|
|
||||||
* be removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class GeoPage<T> extends org.springframework.data.geo.GeoPage<T> {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 23421312312412L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
|
|
||||||
*
|
|
||||||
* @param content must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public GeoPage(GeoResults<T> results) {
|
|
||||||
super(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}, {@link Pageable} and total.
|
|
||||||
*
|
|
||||||
* @param results must not be {@literal null}.
|
|
||||||
* @param pageable must not be {@literal null}.
|
|
||||||
* @param total
|
|
||||||
*/
|
|
||||||
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
|
|
||||||
super(results, pageable, total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calue object capturing some arbitrary object plus a distance.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoResult}. This class is scheduled to
|
|
||||||
* be removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class GeoResult<T> extends org.springframework.data.geo.GeoResult<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link GeoResult} for the given content and distance.
|
|
||||||
*
|
|
||||||
* @param content must not be {@literal null}.
|
|
||||||
* @param distance must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public GeoResult(T content, Distance distance) {
|
|
||||||
super(content, distance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
|
||||||
import org.springframework.data.geo.Distance;
|
|
||||||
import org.springframework.data.geo.GeoResult;
|
|
||||||
import org.springframework.data.geo.Metric;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value object to capture {@link GeoResult}s as well as the average distance they have.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoResults}. This class is scheduled
|
|
||||||
* to be removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class GeoResults<T> extends org.springframework.data.geo.GeoResults<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link GeoResults} instance manually calculating the average distance from the distance values of the
|
|
||||||
* given {@link GeoResult}s.
|
|
||||||
*
|
|
||||||
* @param results must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public GeoResults(List<? extends GeoResult<T>> results) {
|
|
||||||
super(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeoResults(List<? extends GeoResult<T>> results, Metric metric) {
|
|
||||||
super(results, metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link GeoResults} instance from the given {@link GeoResult}s and average distance.
|
|
||||||
*
|
|
||||||
* @param results must not be {@literal null}.
|
|
||||||
* @param averageDistance
|
|
||||||
*/
|
|
||||||
@PersistenceConstructor
|
|
||||||
public GeoResults(List<? extends GeoResult<T>> results, Distance averageDistance) {
|
|
||||||
super(results, averageDistance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commonly used {@link Metrics} for {@link NearQuery}s.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metrics}. This class is scheduled to
|
|
||||||
* be removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public enum Metrics implements Metric {
|
|
||||||
|
|
||||||
KILOMETERS(org.springframework.data.geo.Metrics.KILOMETERS.getMultiplier()), //
|
|
||||||
MILES(org.springframework.data.geo.Metrics.MILES.getMultiplier()), //
|
|
||||||
NEUTRAL(org.springframework.data.geo.Metrics.NEUTRAL.getMultiplier()); //
|
|
||||||
|
|
||||||
private final double multiplier;
|
|
||||||
|
|
||||||
private Metrics(double multiplier) {
|
|
||||||
this.multiplier = multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Metric#getMultiplier()
|
|
||||||
*/
|
|
||||||
public double getMultiplier() {
|
|
||||||
return multiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a geospatial point value.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Point}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Point extends org.springframework.data.geo.Point {
|
|
||||||
|
|
||||||
@PersistenceConstructor
|
|
||||||
public Point(double x, double y) {
|
|
||||||
super(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point(org.springframework.data.geo.Point point) {
|
|
||||||
super(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double[] asArray() {
|
|
||||||
return new double[] { getX(), getY() };
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Double> asList() {
|
|
||||||
return asList(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Double> asList(org.springframework.data.geo.Point point) {
|
|
||||||
return Arrays.asList(point.getX(), point.getY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.geo.Point;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple value object to represent a {@link Polygon}.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Point}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Polygon extends org.springframework.data.geo.Polygon implements Shape {
|
|
||||||
|
|
||||||
public static final String COMMAND = "$polygon";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Polygon} for the given Points.
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
* @param z
|
|
||||||
* @param others
|
|
||||||
*/
|
|
||||||
public <P extends Point> Polygon(P x, P y, P z, P... others) {
|
|
||||||
super(x, y, z, others);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Polygon} for the given Points.
|
|
||||||
*
|
|
||||||
* @param points
|
|
||||||
*/
|
|
||||||
public <P extends Point> Polygon(List<P> points) {
|
|
||||||
super(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
|
||||||
*/
|
|
||||||
public String getCommand() {
|
|
||||||
return COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<? extends Object> asList() {
|
|
||||||
return asList(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link List} of x,y-coordinate tuples of {@link Point}s from the given {@link Polygon}.
|
|
||||||
*
|
|
||||||
* @param polygon
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static List<? extends Object> asList(org.springframework.data.geo.Polygon polygon) {
|
|
||||||
|
|
||||||
List<Point> points = polygon.getPoints();
|
|
||||||
List<List<Double>> tuples = new ArrayList<List<Double>>(points.size());
|
|
||||||
|
|
||||||
for (Point point : points) {
|
|
||||||
tuples.add(Arrays.asList(point.getX(), point.getY()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return tuples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2014 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
|
|
||||||
*
|
|
||||||
* http://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.geo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common interface for all shapes. Allows building MongoDB representations of them.
|
|
||||||
*
|
|
||||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Shape}. This class is scheduled to be
|
|
||||||
* removed in the next major release.
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Thomas Darimont
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public interface Shape extends org.springframework.data.geo.Shape {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link Shape} as a list of usually {@link Double} or {@link List}s of {@link Double}s. Wildcard bound
|
|
||||||
* to allow implementations to return a more concrete element type.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<? extends Object> asList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the command to be used to create the {@literal $within} criterion.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
String getCommand();
|
|
||||||
}
|
|
||||||
@@ -22,6 +22,7 @@ import org.springframework.data.annotation.PersistenceConstructor;
|
|||||||
import org.springframework.data.geo.Circle;
|
import org.springframework.data.geo.Circle;
|
||||||
import org.springframework.data.geo.Distance;
|
import org.springframework.data.geo.Distance;
|
||||||
import org.springframework.data.geo.Point;
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.geo.Shape;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +31,6 @@ import org.springframework.util.Assert;
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class Sphere implements Shape {
|
public class Sphere implements Shape {
|
||||||
|
|
||||||
public static final String COMMAND = "$centerSphere";
|
public static final String COMMAND = "$centerSphere";
|
||||||
@@ -73,23 +73,13 @@ public class Sphere implements Shape {
|
|||||||
this(circle.getCenter(), circle.getRadius());
|
this(circle.getCenter(), circle.getRadius());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Sphere from the given {@link Circle}.
|
|
||||||
*
|
|
||||||
* @param circle
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Sphere(org.springframework.data.mongodb.core.geo.Circle circle) {
|
|
||||||
this(circle.getCenter(), circle.getRadius());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the center of the {@link Circle}.
|
* Returns the center of the {@link Circle}.
|
||||||
*
|
*
|
||||||
* @return will never be {@literal null}.
|
* @return will never be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public org.springframework.data.mongodb.core.geo.Point getCenter() {
|
public Point getCenter() {
|
||||||
return new org.springframework.data.mongodb.core.geo.Point(this.center);
|
return new Point(this.center);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,20 +131,21 @@ public class Sphere implements Shape {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* (non-Javadoc)
|
* Returns the {@link Shape} as a list of usually {@link Double} or {@link List}s of {@link Double}s. Wildcard bound
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
* to allow implementations to return a more concrete element type.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public List<? extends Object> asList() {
|
public List<? extends Object> asList() {
|
||||||
return Arrays.asList(Arrays.asList(center.getX(), center.getY()), this.radius.getValue());
|
return Arrays.asList(Arrays.asList(center.getX(), center.getY()), this.radius.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* (non-Javadoc)
|
* Returns the command to be used to create the {@literal $within} criterion.
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return COMMAND;
|
return COMMAND;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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.
|
||||||
@@ -28,6 +28,7 @@ import java.lang.annotation.Target;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
* @author Johno Crawford
|
* @author Johno Crawford
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Target({ ElementType.TYPE })
|
@Target({ ElementType.TYPE })
|
||||||
@Documented
|
@Documented
|
||||||
@@ -36,11 +37,12 @@ public @interface CompoundIndex {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual index definition in JSON format. The keys of the JSON document are the fields to be indexed, the values
|
* The actual index definition in JSON format. The keys of the JSON document are the fields to be indexed, the values
|
||||||
* define the index direction (1 for ascending, -1 for descending).
|
* define the index direction (1 for ascending, -1 for descending). <br />
|
||||||
|
* If left empty on nested document, the whole document will be indexed.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String def();
|
String def() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It does not actually make sense to use that attribute as the direction has to be defined in the {@link #def()}
|
* It does not actually make sense to use that attribute as the direction has to be defined in the {@link #def()}
|
||||||
@@ -72,18 +74,66 @@ public @interface CompoundIndex {
|
|||||||
boolean dropDups() default false;
|
boolean dropDups() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the index to be created.
|
* The name of the index to be created. <br />
|
||||||
|
* <br />
|
||||||
|
* The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
|
||||||
|
* provided name will be prefixed with the path leading to the entity. <br />
|
||||||
|
* <br />
|
||||||
|
* The structure below
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* @Document
|
||||||
|
* class Root {
|
||||||
|
* Hybrid hybrid;
|
||||||
|
* Nested nested;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Document
|
||||||
|
* @CompoundIndex(name = "compound_index", def = "{'h1': 1, 'h2': 1}")
|
||||||
|
* class Hybrid {
|
||||||
|
* String h1, h2;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @CompoundIndex(name = "compound_index", def = "{'n1': 1, 'n2': 1}")
|
||||||
|
* class Nested {
|
||||||
|
* String n1, n2;
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* resolves in the following index structures
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* db.root.createIndex( { hybrid.h1: 1, hybrid.h2: 1 } , { name: "hybrid.compound_index" } )
|
||||||
|
* db.root.createIndex( { nested.n1: 1, nested.n2: 1 } , { name: "nested.compound_index" } )
|
||||||
|
* db.hybrid.createIndex( { h1: 1, h2: 1 } , { name: "compound_index" } )
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to {@literal true} then MongoDB will ignore the given index name and instead generate a new name. Defaults
|
||||||
|
* to {@literal false}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
boolean useGeneratedName() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection the index will be created in. Will default to the collection the annotated domain class will be
|
* The collection the index will be created in. Will default to the collection the annotated domain class will be
|
||||||
* stored in.
|
* stored in.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||||
|
* result in broken definitions. Will be removed in 1.7.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String collection() default "";
|
String collection() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,11 +144,4 @@ public @interface CompoundIndex {
|
|||||||
*/
|
*/
|
||||||
boolean background() default false;
|
boolean background() default false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the number of seconds after which the collection should expire. Defaults to -1 for no expiry.
|
|
||||||
*
|
|
||||||
* @see http://docs.mongodb.org/manual/tutorial/expire-data/
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
int expireAfterSeconds() default -1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.index;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index definition to span multiple keys.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public class CompoundIndexDefinition extends Index {
|
||||||
|
|
||||||
|
private DBObject keys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link CompoundIndexDefinition} for the given keys.
|
||||||
|
*
|
||||||
|
* @param keys must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public CompoundIndexDefinition(DBObject keys) {
|
||||||
|
|
||||||
|
Assert.notNull(keys, "Keys must not be null!");
|
||||||
|
this.keys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.index.Index#getIndexKeys()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject getIndexKeys() {
|
||||||
|
|
||||||
|
BasicDBObject dbo = new BasicDBObject();
|
||||||
|
dbo.putAll(this.keys);
|
||||||
|
dbo.putAll(super.getIndexKeys());
|
||||||
|
return dbo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2015 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,23 +25,71 @@ import java.lang.annotation.Target;
|
|||||||
*
|
*
|
||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Laurent Canet
|
* @author Laurent Canet
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface GeoSpatialIndexed {
|
public @interface GeoSpatialIndexed {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the property in the document that contains the [x, y] or radial coordinates to index.
|
* Index name. <br />
|
||||||
|
* <br />
|
||||||
|
* The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
|
||||||
|
* provided name will be prefixed with the path leading to the entity. <br />
|
||||||
|
* <br />
|
||||||
|
* The structure below
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* @Document
|
||||||
|
* class Root {
|
||||||
|
* Hybrid hybrid;
|
||||||
|
* Nested nested;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Document
|
||||||
|
* class Hybrid {
|
||||||
|
* @GeoSpatialIndexed(name="index") Point h1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class Nested {
|
||||||
|
* @GeoSpatialIndexed(name="index") Point n1;
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* resolves in the following index structures
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* db.root.createIndex( { hybrid.h1: "2d" } , { name: "hybrid.index" } )
|
||||||
|
* db.root.createIndex( { nested.n1: "2d" } , { name: "nested.index" } )
|
||||||
|
* db.hybrid.createIndex( { h1: "2d" } , { name: "index" } )
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to {@literal true} then MongoDB will ignore the given index name and instead generate a new name. Defaults
|
||||||
|
* to {@literal false}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
boolean useGeneratedName() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the collection in which to create the index.
|
* Name of the collection in which to create the index.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||||
|
* result in broken definitions. Will be removed in 1.7.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String collection() default "";
|
String collection() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2014 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,6 +27,7 @@ import com.mongodb.DBObject;
|
|||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Laurent Canet
|
* @author Laurent Canet
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class GeospatialIndex implements IndexDefinition {
|
public class GeospatialIndex implements IndexDefinition {
|
||||||
|
|
||||||
@@ -57,8 +58,6 @@ public class GeospatialIndex implements IndexDefinition {
|
|||||||
*/
|
*/
|
||||||
public GeospatialIndex named(String name) {
|
public GeospatialIndex named(String name) {
|
||||||
|
|
||||||
Assert.hasText(name, "Name must have text!");
|
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -151,12 +150,12 @@ public class GeospatialIndex implements IndexDefinition {
|
|||||||
|
|
||||||
public DBObject getIndexOptions() {
|
public DBObject getIndexOptions() {
|
||||||
|
|
||||||
if (name == null && min == null && max == null && bucketSize == null) {
|
if (!StringUtils.hasText(name) && min == null && max == null && bucketSize == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
if (name != null) {
|
if (StringUtils.hasText(name)) {
|
||||||
dbo.put("name", name);
|
dbo.put("name", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +185,7 @@ public class GeospatialIndex implements IndexDefinition {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2010-2014 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,18 +17,35 @@ package org.springframework.data.mongodb.core.index;
|
|||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.springframework.data.domain.Sort.Direction;
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
import org.springframework.data.mongodb.core.query.Order;
|
import org.springframework.data.mongodb.core.query.Order;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class Index implements IndexDefinition {
|
public class Index implements IndexDefinition {
|
||||||
|
|
||||||
public enum Duplicates {
|
public enum Duplicates {
|
||||||
RETAIN, DROP
|
RETAIN, //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dropping Duplicates was removed in MongoDB Server 2.8.0-rc0.
|
||||||
|
* <p>
|
||||||
|
* See https://jira.mongodb.org/browse/SERVER-14710
|
||||||
|
*
|
||||||
|
* @deprecated since 1.7.
|
||||||
|
*/
|
||||||
|
@Deprecated//
|
||||||
|
DROP
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, Direction> fieldSpec = new LinkedHashMap<String, Direction>();
|
private final Map<String, Direction> fieldSpec = new LinkedHashMap<String, Direction>();
|
||||||
@@ -41,6 +58,10 @@ public class Index implements IndexDefinition {
|
|||||||
|
|
||||||
private boolean sparse = false;
|
private boolean sparse = false;
|
||||||
|
|
||||||
|
private boolean background = false;
|
||||||
|
|
||||||
|
private long expire = -1;
|
||||||
|
|
||||||
public Index() {}
|
public Index() {}
|
||||||
|
|
||||||
public Index(String key, Direction direction) {
|
public Index(String key, Direction direction) {
|
||||||
@@ -104,6 +125,44 @@ public class Index implements IndexDefinition {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the index in background (non blocking).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public Index background() {
|
||||||
|
|
||||||
|
this.background = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies TTL in seconds.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public Index expire(long value) {
|
||||||
|
return expire(value, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies TTL with given {@link TimeUnit}.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @param unit
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public Index expire(long value, TimeUnit unit) {
|
||||||
|
|
||||||
|
Assert.notNull(unit, "TimeUnit for expiration must not be null.");
|
||||||
|
this.expire = unit.toSeconds(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see http://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping
|
* @see http://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping
|
||||||
* @param duplicates
|
* @param duplicates
|
||||||
@@ -125,11 +184,9 @@ public class Index implements IndexDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DBObject getIndexOptions() {
|
public DBObject getIndexOptions() {
|
||||||
if (name == null && !unique) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
if (name != null) {
|
if (StringUtils.hasText(name)) {
|
||||||
dbo.put("name", name);
|
dbo.put("name", name);
|
||||||
}
|
}
|
||||||
if (unique) {
|
if (unique) {
|
||||||
@@ -141,6 +198,13 @@ public class Index implements IndexDefinition {
|
|||||||
if (sparse) {
|
if (sparse) {
|
||||||
dbo.put("sparse", true);
|
dbo.put("sparse", true);
|
||||||
}
|
}
|
||||||
|
if (background) {
|
||||||
|
dbo.put("background", true);
|
||||||
|
}
|
||||||
|
if (expire >= 0) {
|
||||||
|
dbo.put("expireAfterSeconds", expire);
|
||||||
|
}
|
||||||
|
|
||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 by the original author(s).
|
* Copyright (c) 2011-2014 by the original author(s).
|
||||||
*
|
*
|
||||||
* 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,11 +20,11 @@ import com.mongodb.DBObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public interface IndexDefinition {
|
public interface IndexDefinition {
|
||||||
|
|
||||||
DBObject getIndexKeys();
|
DBObject getIndexKeys();
|
||||||
|
|
||||||
DBObject getIndexOptions();
|
DBObject getIndexOptions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2013 the original author or authors.
|
* Copyright 2012-2014 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,22 +24,33 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* Value object for an index field.
|
* Value object for an index field.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public final class IndexField {
|
public final class IndexField {
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
GEO, TEXT, DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
private final Direction direction;
|
private final Direction direction;
|
||||||
private final boolean isGeo;
|
private final Type type;
|
||||||
|
private final Float weight;
|
||||||
|
|
||||||
private IndexField(String key, Direction direction, boolean isGeo) {
|
private IndexField(String key, Direction direction, Type type) {
|
||||||
|
this(key, direction, type, Float.NaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndexField(String key, Direction direction, Type type, Float weight) {
|
||||||
|
|
||||||
Assert.hasText(key);
|
Assert.hasText(key);
|
||||||
Assert.isTrue(direction != null ^ isGeo);
|
Assert.isTrue(direction != null ^ (Type.GEO.equals(type) || Type.TEXT.equals(type)));
|
||||||
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
this.isGeo = isGeo;
|
this.type = type == null ? Type.DEFAULT : type;
|
||||||
|
this.weight = weight == null ? Float.NaN : weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,12 +64,12 @@ public final class IndexField {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public static IndexField create(String key, Order order) {
|
public static IndexField create(String key, Order order) {
|
||||||
Assert.notNull(order);
|
Assert.notNull(order);
|
||||||
return new IndexField(key, order.toDirection(), false);
|
return new IndexField(key, order.toDirection(), Type.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IndexField create(String key, Direction order) {
|
public static IndexField create(String key, Direction order) {
|
||||||
Assert.notNull(order);
|
Assert.notNull(order);
|
||||||
return new IndexField(key, order, false);
|
return new IndexField(key, order, Type.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +79,16 @@ public final class IndexField {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static IndexField geo(String key) {
|
public static IndexField geo(String key) {
|
||||||
return new IndexField(key, null, true);
|
return new IndexField(key, null, Type.GEO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a text {@link IndexField} for the given key.
|
||||||
|
*
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public static IndexField text(String key, Float weight) {
|
||||||
|
return new IndexField(key, null, Type.TEXT, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,10 +121,20 @@ public final class IndexField {
|
|||||||
/**
|
/**
|
||||||
* Returns whether the {@link IndexField} is a geo index field.
|
* Returns whether the {@link IndexField} is a geo index field.
|
||||||
*
|
*
|
||||||
* @return the isGeo
|
* @return true if type is {@link Type#GEO}.
|
||||||
*/
|
*/
|
||||||
public boolean isGeo() {
|
public boolean isGeo() {
|
||||||
return isGeo;
|
return Type.GEO.equals(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns wheter the {@link IndexField} is a text index field.
|
||||||
|
*
|
||||||
|
* @return true if type is {@link Type#TEXT}
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public boolean isText() {
|
||||||
|
return Type.TEXT.equals(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -125,7 +155,7 @@ public final class IndexField {
|
|||||||
IndexField that = (IndexField) obj;
|
IndexField that = (IndexField) obj;
|
||||||
|
|
||||||
return this.key.equals(that.key) && ObjectUtils.nullSafeEquals(this.direction, that.direction)
|
return this.key.equals(that.key) && ObjectUtils.nullSafeEquals(this.direction, that.direction)
|
||||||
&& this.isGeo == that.isGeo;
|
&& this.type == that.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -138,7 +168,8 @@ public final class IndexField {
|
|||||||
int result = 17;
|
int result = 17;
|
||||||
result += 31 * ObjectUtils.nullSafeHashCode(key);
|
result += 31 * ObjectUtils.nullSafeHashCode(key);
|
||||||
result += 31 * ObjectUtils.nullSafeHashCode(direction);
|
result += 31 * ObjectUtils.nullSafeHashCode(direction);
|
||||||
result += 31 * ObjectUtils.nullSafeHashCode(isGeo);
|
result += 31 * ObjectUtils.nullSafeHashCode(type);
|
||||||
|
result += 31 * ObjectUtils.nullSafeHashCode(weight);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +179,7 @@ public final class IndexField {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("IndexField [ key: %s, direction: %s, isGeo: %s]", key, direction, isGeo);
|
return String.format("IndexField [ key: %s, direction: %s, type: %s, weight: %s]", key, direction, type, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2011 the original author or authors.
|
* Copyright 2002-2014 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.
|
||||||
@@ -23,6 +23,11 @@ import java.util.List;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mark Pollack
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
public class IndexInfo {
|
public class IndexInfo {
|
||||||
|
|
||||||
private final List<IndexField> indexFields;
|
private final List<IndexField> indexFields;
|
||||||
@@ -31,14 +36,30 @@ public class IndexInfo {
|
|||||||
private final boolean unique;
|
private final boolean unique;
|
||||||
private final boolean dropDuplicates;
|
private final boolean dropDuplicates;
|
||||||
private final boolean sparse;
|
private final boolean sparse;
|
||||||
|
private final String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Will be removed in 1.7. Please use {@link #IndexInfo(List, String, boolean, boolean, boolean, String)}
|
||||||
|
* @param indexFields
|
||||||
|
* @param name
|
||||||
|
* @param unique
|
||||||
|
* @param dropDuplicates
|
||||||
|
* @param sparse
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse) {
|
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse) {
|
||||||
|
this(indexFields, name, unique, dropDuplicates, sparse, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse,
|
||||||
|
String language) {
|
||||||
|
|
||||||
this.indexFields = Collections.unmodifiableList(indexFields);
|
this.indexFields = Collections.unmodifiableList(indexFields);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.unique = unique;
|
this.unique = unique;
|
||||||
this.dropDuplicates = dropDuplicates;
|
this.dropDuplicates = dropDuplicates;
|
||||||
this.sparse = sparse;
|
this.sparse = sparse;
|
||||||
|
this.language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,14 +105,23 @@ public class IndexInfo {
|
|||||||
return sparse;
|
return sparse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
|
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
|
||||||
+ dropDuplicates + ", sparse=" + sparse + "]";
|
+ dropDuplicates + ", sparse=" + sparse + ", language=" + language + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + (dropDuplicates ? 1231 : 1237);
|
result = prime * result + (dropDuplicates ? 1231 : 1237);
|
||||||
@@ -99,6 +129,7 @@ public class IndexInfo {
|
|||||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
result = prime * result + (sparse ? 1231 : 1237);
|
result = prime * result + (sparse ? 1231 : 1237);
|
||||||
result = prime * result + (unique ? 1231 : 1237);
|
result = prime * result + (unique ? 1231 : 1237);
|
||||||
|
result = prime * result + ObjectUtils.nullSafeHashCode(language);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +168,9 @@ public class IndexInfo {
|
|||||||
if (unique != other.unique) {
|
if (unique != other.unique) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!ObjectUtils.nullSafeEquals(language, other.language)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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
|
||||||
|
*
|
||||||
|
* http://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.index;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IndexResolver} finds those {@link IndexDefinition}s to be created for a given class.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
interface IndexResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and create {@link IndexDefinition}s for properties of given {@code type}. {@link IndexDefinition}s are created
|
||||||
|
* for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
|
||||||
|
*/
|
||||||
|
Iterable<? extends IndexDefinitionHolder> resolveIndexForClass(Class<?> type);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-2015 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,6 +27,8 @@ import java.lang.annotation.Target;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
* @author Johno Crawford
|
* @author Johno Crawford
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@@ -57,17 +59,63 @@ public @interface Indexed {
|
|||||||
boolean dropDups() default false;
|
boolean dropDups() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index name.
|
* Index name. <br />
|
||||||
|
* <br />
|
||||||
|
* The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
|
||||||
|
* provided name will be prefixed with the path leading to the entity. <br />
|
||||||
|
* <br />
|
||||||
|
* The structure below
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* @Document
|
||||||
|
* class Root {
|
||||||
|
* Hybrid hybrid;
|
||||||
|
* Nested nested;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Document
|
||||||
|
* class Hybrid {
|
||||||
|
* @Indexed(name="index") String h1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class Nested {
|
||||||
|
* @Indexed(name="index") String n1;
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* resolves in the following index structures
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* db.root.createIndex( { hybrid.h1: 1 } , { name: "hybrid.index" } )
|
||||||
|
* db.root.createIndex( { nested.n1: 1 } , { name: "nested.index" } )
|
||||||
|
* db.hybrid.createIndex( { h1: 1} , { name: "index" } )
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Colleciton name for index to be created on.
|
* If set to {@literal true} then MongoDB will ignore the given index name and instead generate a new name. Defaults
|
||||||
|
* to {@literal false}.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
|
boolean useGeneratedName() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection name for index to be created on.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||||
|
* result in broken definitions. Will be removed in 1.7.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
String collection() default "";
|
String collection() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,19 +22,15 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.mapping.PersistentEntity;
|
||||||
import org.springframework.data.mapping.PropertyHandler;
|
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.context.MappingContextEvent;
|
import org.springframework.data.mapping.context.MappingContextEvent;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||||
|
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.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
|
||||||
import com.mongodb.DBObject;
|
|
||||||
import com.mongodb.util.JSON;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that inspects {@link MongoPersistentEntity} instances contained in the given {@link MongoMappingContext}
|
* Component that inspects {@link MongoPersistentEntity} instances contained in the given {@link MongoMappingContext}
|
||||||
@@ -45,6 +41,7 @@ import com.mongodb.util.JSON;
|
|||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
* @author Johno Crawford
|
* @author Johno Crawford
|
||||||
* @author Laurent Canet
|
* @author Laurent Canet
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MongoPersistentEntityIndexCreator implements
|
public class MongoPersistentEntityIndexCreator implements
|
||||||
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
||||||
@@ -54,21 +51,37 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<Class<?>, Boolean>();
|
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<Class<?>, Boolean>();
|
||||||
private final MongoDbFactory mongoDbFactory;
|
private final MongoDbFactory mongoDbFactory;
|
||||||
private final MongoMappingContext mappingContext;
|
private final MongoMappingContext mappingContext;
|
||||||
|
private final IndexResolver indexResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||||
* {@link MongoDbFactory}.
|
* {@link MongoDbFactory}.
|
||||||
*
|
*
|
||||||
* @param mappingContext must not be {@literal null}
|
* @param mappingContext must not be {@literal null}.
|
||||||
* @param mongoDbFactory must not be {@literal null}
|
* @param mongoDbFactory must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) {
|
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) {
|
||||||
|
this(mappingContext, mongoDbFactory, new MongoPersistentEntityIndexResolver(mappingContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||||
|
* {@link MongoDbFactory}.
|
||||||
|
*
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
* @param mongoDbFactory must not be {@literal null}.
|
||||||
|
* @param indexResolver must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory,
|
||||||
|
IndexResolver indexResolver) {
|
||||||
|
|
||||||
Assert.notNull(mongoDbFactory);
|
Assert.notNull(mongoDbFactory);
|
||||||
Assert.notNull(mappingContext);
|
Assert.notNull(mappingContext);
|
||||||
|
Assert.notNull(indexResolver);
|
||||||
|
|
||||||
this.mongoDbFactory = mongoDbFactory;
|
this.mongoDbFactory = mongoDbFactory;
|
||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
|
this.indexResolver = indexResolver;
|
||||||
|
|
||||||
for (MongoPersistentEntity<?> entity : mappingContext.getPersistentEntities()) {
|
for (MongoPersistentEntity<?> entity : mappingContext.getPersistentEntities()) {
|
||||||
checkForIndexes(entity);
|
checkForIndexes(entity);
|
||||||
@@ -93,85 +106,34 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkForIndexes(final MongoPersistentEntity<?> entity) {
|
private void checkForIndexes(final MongoPersistentEntity<?> entity) {
|
||||||
final Class<?> type = entity.getType();
|
|
||||||
|
Class<?> type = entity.getType();
|
||||||
|
|
||||||
if (!classesSeen.containsKey(type)) {
|
if (!classesSeen.containsKey(type)) {
|
||||||
|
|
||||||
|
this.classesSeen.put(type, Boolean.TRUE);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("Analyzing class " + type + " for index information.");
|
LOGGER.debug("Analyzing class " + type + " for index information.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure indexes get created
|
checkForAndCreateIndexes(entity);
|
||||||
if (type.isAnnotationPresent(CompoundIndexes.class)) {
|
}
|
||||||
CompoundIndexes indexes = type.getAnnotation(CompoundIndexes.class);
|
}
|
||||||
for (CompoundIndex index : indexes.value()) {
|
|
||||||
|
|
||||||
String indexColl = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
private void checkForAndCreateIndexes(MongoPersistentEntity<?> entity) {
|
||||||
DBObject definition = (DBObject) JSON.parse(index.def());
|
|
||||||
|
|
||||||
ensureIndex(indexColl, index.name(), definition, index.unique(), index.dropDups(), index.sparse(),
|
if (entity.findAnnotation(Document.class) != null) {
|
||||||
index.background(), index.expireAfterSeconds());
|
for (IndexDefinitionHolder indexToCreate : indexResolver.resolveIndexForClass(entity.getType())) {
|
||||||
|
createIndex(indexToCreate);
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("Created compound index " + index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
private void createIndex(IndexDefinitionHolder indexDefinition) {
|
||||||
public void doWithPersistentProperty(MongoPersistentProperty property) {
|
mongoDbFactory.getDb().getCollection(indexDefinition.getCollection())
|
||||||
|
.createIndex(indexDefinition.getIndexKeys(), indexDefinition.getIndexOptions());
|
||||||
if (property.isAnnotationPresent(Indexed.class)) {
|
|
||||||
|
|
||||||
Indexed index = property.findAnnotation(Indexed.class);
|
|
||||||
String name = index.name();
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(name)) {
|
|
||||||
name = property.getFieldName();
|
|
||||||
} else {
|
|
||||||
if (!name.equals(property.getName()) && index.unique() && !index.sparse()) {
|
|
||||||
// Names don't match, and sparse is not true. This situation will generate an error on the server.
|
|
||||||
if (LOGGER.isWarnEnabled()) {
|
|
||||||
LOGGER.warn("The index name " + name + " doesn't match this property name: " + property.getName()
|
|
||||||
+ ". Setting sparse=true on this index will prevent errors when inserting documents.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
|
||||||
int direction = index.direction() == IndexDirection.ASCENDING ? 1 : -1;
|
|
||||||
DBObject definition = new BasicDBObject(property.getFieldName(), direction);
|
|
||||||
|
|
||||||
ensureIndex(collection, name, definition, index.unique(), index.dropDups(), index.sparse(),
|
|
||||||
index.background(), index.expireAfterSeconds());
|
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("Created property index " + index);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (property.isAnnotationPresent(GeoSpatialIndexed.class)) {
|
|
||||||
|
|
||||||
GeoSpatialIndexed index = property.findAnnotation(GeoSpatialIndexed.class);
|
|
||||||
|
|
||||||
GeospatialIndex indexObject = new GeospatialIndex(property.getFieldName());
|
|
||||||
indexObject.withMin(index.min()).withMax(index.max());
|
|
||||||
indexObject.named(StringUtils.hasText(index.name()) ? index.name() : property.getName());
|
|
||||||
indexObject.typed(index.type()).withBucketSize(index.bucketSize())
|
|
||||||
.withAdditionalField(index.additionalField());
|
|
||||||
|
|
||||||
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
|
||||||
mongoDbFactory.getDb().getCollection(collection)
|
|
||||||
.ensureIndex(indexObject.getIndexKeys(), indexObject.getIndexOptions());
|
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug(String.format("Created %s for entity %s in collection %s! ", indexObject, entity.getType(),
|
|
||||||
collection));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
classesSeen.put(type, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,33 +145,4 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
public boolean isIndexCreatorFor(MappingContext<?, ?> context) {
|
public boolean isIndexCreatorFor(MappingContext<?, ?> context) {
|
||||||
return this.mappingContext.equals(context);
|
return this.mappingContext.equals(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers the actual index creation.
|
|
||||||
*
|
|
||||||
* @param collection the collection to create the index in
|
|
||||||
* @param name the name of the index about to be created
|
|
||||||
* @param indexDefinition the index definition
|
|
||||||
* @param unique whether it shall be a unique index
|
|
||||||
* @param dropDups whether to drop duplicates
|
|
||||||
* @param sparse sparse or not
|
|
||||||
* @param background whether the index will be created in the background
|
|
||||||
* @param expireAfterSeconds the time to live for documents in the collection
|
|
||||||
*/
|
|
||||||
protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique,
|
|
||||||
boolean dropDups, boolean sparse, boolean background, int expireAfterSeconds) {
|
|
||||||
|
|
||||||
DBObject opts = new BasicDBObject();
|
|
||||||
opts.put("name", name);
|
|
||||||
opts.put("dropDups", dropDups);
|
|
||||||
opts.put("sparse", sparse);
|
|
||||||
opts.put("unique", unique);
|
|
||||||
opts.put("background", background);
|
|
||||||
|
|
||||||
if (expireAfterSeconds != -1) {
|
|
||||||
opts.put("expireAfterSeconds", expireAfterSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
mongoDbFactory.getDb().getCollection(collection).ensureIndex(indexDefinition, opts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user