Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22933e4493 | ||
|
|
40aa6bbdd5 | ||
|
|
5e43f5846a | ||
|
|
2cfd4781bc | ||
|
|
031ab0c07b | ||
|
|
10f69f6623 | ||
|
|
d7b03915a7 | ||
|
|
ed55d48a53 | ||
|
|
d5ed4e0ac2 | ||
|
|
75194730e9 | ||
|
|
a09183d2eb | ||
|
|
45dd3cd988 | ||
|
|
b24e34c360 | ||
|
|
fa9b5efdab | ||
|
|
8f2ced8ada | ||
|
|
ff92cf1429 | ||
|
|
ba48290a3e | ||
|
|
70e5efd0d9 | ||
|
|
4eae229bff | ||
|
|
47f0607c49 | ||
|
|
753e794194 | ||
|
|
d27bec8ed5 | ||
|
|
c63f7f75dc | ||
|
|
84040518cf | ||
|
|
c66b9a538c | ||
|
|
a0c6b9aa64 | ||
|
|
9370c1ee01 | ||
|
|
2839e9491f | ||
|
|
6963f9e07a | ||
|
|
8dd08a36a0 | ||
|
|
a908e89ef7 | ||
|
|
5ace4032ed | ||
|
|
621b299f6f | ||
|
|
a2628d1b74 | ||
|
|
294616432d | ||
|
|
47dd512f95 | ||
|
|
f16e8d85e5 | ||
|
|
eb03ae61f2 | ||
|
|
5be66a3fee | ||
|
|
d88e4c0e3e | ||
|
|
57d1449008 | ||
|
|
8d00a0d926 | ||
|
|
e3fa844488 | ||
|
|
58bee75a6b | ||
|
|
a402395f5c | ||
|
|
9d5f8f3ba0 | ||
|
|
7ebf953063 | ||
|
|
617ebe0ca7 | ||
|
|
7f76789664 | ||
|
|
81e5919ace | ||
|
|
efd74956dc | ||
|
|
49eee40f7e | ||
|
|
8e93b844c7 | ||
|
|
3e64432f1a | ||
|
|
88c968ad36 | ||
|
|
99eefe0773 | ||
|
|
3d4569be14 | ||
|
|
57455c4a26 | ||
|
|
f9e20d12b2 | ||
|
|
4d6152c65e | ||
|
|
d81cc53c12 | ||
|
|
af4b84ea43 | ||
|
|
f9110828bc | ||
|
|
f301837be5 | ||
|
|
4d29d937eb | ||
|
|
86c11bc614 | ||
|
|
be34b4e503 | ||
|
|
ebfa2c5689 | ||
|
|
b245ef2d9e | ||
|
|
5ef40d54bc | ||
|
|
c679dba438 | ||
|
|
fd6e4000b5 | ||
|
|
c12a27a8f8 | ||
|
|
df2184f204 | ||
|
|
e9c8644d23 | ||
|
|
c730b8f479 | ||
|
|
f3b31fc467 | ||
|
|
f778b2554c | ||
|
|
9d292f64b9 | ||
|
|
8ab038f83c | ||
|
|
689552c28e | ||
|
|
9ea9912b23 | ||
|
|
a952ce5d2b | ||
|
|
b88d960893 | ||
|
|
e44d1f5f9a | ||
|
|
2b5e2361a8 | ||
|
|
5737f2d19d | ||
|
|
60494a6904 | ||
|
|
ceb561e3e4 | ||
|
|
e2d0220cea | ||
|
|
ea33e8b8c6 | ||
|
|
506b6a2e85 | ||
|
|
7c0eee9e09 | ||
|
|
332e5eb715 | ||
|
|
39ee9b56e2 | ||
|
|
8fb390ee88 | ||
|
|
df1c4496dc | ||
|
|
b808fd3003 | ||
|
|
ed12298271 | ||
|
|
682798325b | ||
|
|
0e69021486 | ||
|
|
ae7e24f1b6 | ||
|
|
94d4fa613c | ||
|
|
39c9593b39 | ||
|
|
6e5f3661a8 | ||
|
|
2bd78e0bf0 | ||
|
|
dd59cdc59a | ||
|
|
7e471e2301 | ||
|
|
0871a43831 | ||
|
|
710e77dabe | ||
|
|
9c996617e8 | ||
|
|
eebd49ab8d | ||
|
|
fb979b1734 | ||
|
|
b5c88938e0 | ||
|
|
4027770701 | ||
|
|
a120ce2bb1 | ||
|
|
a5d40a049d | ||
|
|
f0f12d5296 | ||
|
|
24e06cf219 | ||
|
|
1b83ff0382 | ||
|
|
fe41202f96 | ||
|
|
78235b4799 | ||
|
|
51ece4353b | ||
|
|
51bab838b0 | ||
|
|
361f9daa45 | ||
|
|
56b23a6dbe | ||
|
|
9e15c17e26 | ||
|
|
a3c77a43b6 | ||
|
|
55169e2e11 | ||
|
|
24672e6bdd | ||
|
|
1a46abfbb9 | ||
|
|
61284228dd | ||
|
|
8cb92de1ee | ||
|
|
5d3cc3fa04 | ||
|
|
c0b99740dc | ||
|
|
595bbd3aa7 | ||
|
|
5d2fc31164 | ||
|
|
a9dc0fae69 | ||
|
|
0605c7b753 | ||
|
|
21352a8829 | ||
|
|
58e1d2dbd9 | ||
|
|
4f7821e3c2 |
1
CONTRIBUTING.MD
Normal file
1
CONTRIBUTING.MD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
You find the contribution guidelines for Spring Data projects [here](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.md).
|
||||||
30
README.md
30
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Spring Data MongoDB
|
# Spring Data MongoDB
|
||||||
|
|
||||||
The primary goal of the [Spring Data](http://www.springsource.org/spring-data) project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
|
The primary goal of the [Spring Data](http://projects.spring.io/spring-data) project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
|
||||||
|
|
||||||
The Spring Data MongoDB project aims to provide a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities. The Spring Data MongoDB project provides integration with the MongoDB document database. Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB DBCollection and easily writing a repository style data access layer.
|
The Spring Data MongoDB project aims to provide a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities. The Spring Data MongoDB project provides integration with the MongoDB document database. Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB DBCollection and easily writing a repository style data access layer.
|
||||||
|
|
||||||
@@ -8,12 +8,12 @@ The Spring Data MongoDB project aims to provide a familiar and consistent Spring
|
|||||||
|
|
||||||
For a comprehensive treatment of all the Spring Data MongoDB features, please refer to:
|
For a comprehensive treatment of all the Spring Data MongoDB features, please refer to:
|
||||||
|
|
||||||
* the [User Guide](http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/)
|
* the [User Guide](http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/)
|
||||||
* the [JavaDocs](http://static.springsource.org/spring-data/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://www.springsource.org/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.springsource.org/forumdisplay.php?f=80).
|
* for more detailed questions, use the [forum](http://forum.spring.io/forum/spring-projects/data/nosql).
|
||||||
|
|
||||||
If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects).
|
If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://projects.spring.io/).
|
||||||
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
@@ -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.2.3.RELEASE</version>
|
<version>1.4.1.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -36,13 +36,13 @@ 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.3.0.BUILD-SNAPSHOT</version>
|
<version>1.5.0.BUILD-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-libs-snapshot</id>
|
<id>spring-libs-snapshot</id>
|
||||||
<name>Spring Snapshot Repository</name>
|
<name>Spring Snapshot Repository</name>
|
||||||
<url>http://repo.springsource.org/libs-snapshot</url>
|
<url>http://repo.spring.io/libs-snapshot</url>
|
||||||
</repository>
|
</repository>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ MongoTemplate is the central support class for Mongo database operations. It pro
|
|||||||
* Basic POJO mapping support to and from BSON
|
* Basic POJO mapping support to and from BSON
|
||||||
* Convenience methods to interact with the store (insert object, update objects) and MongoDB specific ones (geo-spatial operations, upserts, map-reduce etc.)
|
* Convenience methods to interact with the store (insert object, update objects) and MongoDB specific ones (geo-spatial operations, upserts, map-reduce etc.)
|
||||||
* Connection affinity callback
|
* Connection affinity callback
|
||||||
* Exception translation into Spring's [technology agnostic DAO exception hierarchy](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/dao.html#dao-exceptions).
|
* Exception translation into Spring's [technology agnostic DAO exception hierarchy](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/dao.html#dao-exceptions).
|
||||||
|
|
||||||
### Spring Data repositories
|
### Spring Data repositories
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class ApplicationConfig extends AbstractMongoConfiguration {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mongo mongo() throws Exception {
|
public Mongo mongo() throws Exception {
|
||||||
return new Mongo();
|
return new MongoClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,9 +94,9 @@ class ApplicationConfig extends AbstractMongoConfiguration {
|
|||||||
This sets up a connection to a local MongoDB instance and enables the detection of Spring Data repositories (through `@EnableMongoRepositories`). The same configuration would look like this in XML:
|
This sets up a connection to a local MongoDB instance and enables the detection of Spring Data repositories (through `@EnableMongoRepositories`). The same configuration would look like this in XML:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<bean id="template" class="org.springframework.data.document.mongodb.MongoTemplate">
|
<bean id="template" class="org.springframework.data.mongodb.core.MongoTemplate">
|
||||||
<constructor-arg>
|
<constructor-arg>
|
||||||
<bean class="com.mongodb.Mongo">
|
<bean class="com.mongodb.MongoClient">
|
||||||
<constructor-arg value="localhost" />
|
<constructor-arg value="localhost" />
|
||||||
<constructor-arg value="27017" />
|
<constructor-arg value="27017" />
|
||||||
</bean>
|
</bean>
|
||||||
@@ -139,9 +139,9 @@ 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.springsource.org/forumdisplay.php?f=80) by responding to questions and joining the debate.
|
* 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.
|
||||||
* 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://www.springsource.org/node/feed) to springframework.org
|
* Watch for upcoming articles on Spring by [subscribing](http://spring.io/blog) to spring.io.
|
||||||
|
|
||||||
Before we accept a non-trivial patch or pull request we will need you to sign the [contributor's agreement](https://support.springsource.com/spring_committer_signup). Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
|
Before we accept a non-trivial patch or pull request we will need you to sign the [contributor's agreement](https://support.springsource.com/spring_committer_signup). Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
|
||||||
|
|||||||
80
pom.xml
80
pom.xml
@@ -5,20 +5,20 @@
|
|||||||
|
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.3.0.RC1</version>
|
<version>1.5.0.M1</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
<description>MongoDB support for Spring Data</description>
|
<description>MongoDB support for Spring Data</description>
|
||||||
<url>http://www.springsource.org/spring-data/mongodb</url>
|
<url>http://projects.spring.io/spring-data-mongodb</url>
|
||||||
|
|
||||||
<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.1.1.RELEASE</version>
|
<version>1.4.0.M1</version>
|
||||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>spring-data-mongodb</module>
|
<module>spring-data-mongodb</module>
|
||||||
<module>spring-data-mongodb-cross-store</module>
|
<module>spring-data-mongodb-cross-store</module>
|
||||||
@@ -29,19 +29,20 @@
|
|||||||
<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.6.0.RC1</springdata.commons>
|
<springdata.commons>1.8.0.M1</springdata.commons>
|
||||||
<mongo>2.10.1</mongo>
|
<mongo>2.11.4</mongo>
|
||||||
|
<mongo-osgi>${mongo}</mongo-osgi>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<id>ogierke</id>
|
<id>ogierke</id>
|
||||||
<name>Oliver Gierke</name>
|
<name>Oliver Gierke</name>
|
||||||
<email>ogierke at vmware.com</email>
|
<email>ogierke at gopivotal.com</email>
|
||||||
<organization>SpringSource</organization>
|
<organization>Pivotal</organization>
|
||||||
<organizationUrl>http://www.springsource.com</organizationUrl>
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
<roles>
|
<roles>
|
||||||
<role>Project Lean</role>
|
<role>Project Lead</role>
|
||||||
</roles>
|
</roles>
|
||||||
<timezone>+1</timezone>
|
<timezone>+1</timezone>
|
||||||
</developer>
|
</developer>
|
||||||
@@ -49,8 +50,8 @@
|
|||||||
<id>trisberg</id>
|
<id>trisberg</id>
|
||||||
<name>Thomas Risberg</name>
|
<name>Thomas Risberg</name>
|
||||||
<email>trisberg at vmware.com</email>
|
<email>trisberg at vmware.com</email>
|
||||||
<organization>SpringSource</organization>
|
<organization>Pivotal</organization>
|
||||||
<organizationUrl>http://www.springsource.com</organizationUrl>
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
<roles>
|
<roles>
|
||||||
<role>Developer</role>
|
<role>Developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
@@ -59,9 +60,9 @@
|
|||||||
<developer>
|
<developer>
|
||||||
<id>mpollack</id>
|
<id>mpollack</id>
|
||||||
<name>Mark Pollack</name>
|
<name>Mark Pollack</name>
|
||||||
<email>mpollack at vmware.com</email>
|
<email>mpollack at gopivotal.com</email>
|
||||||
<organization>SpringSource</organization>
|
<organization>Pivotal</organization>
|
||||||
<organizationUrl>http://www.springsource.com</organizationUrl>
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
<roles>
|
<roles>
|
||||||
<role>Developer</role>
|
<role>Developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
@@ -70,16 +71,48 @@
|
|||||||
<developer>
|
<developer>
|
||||||
<id>jbrisbin</id>
|
<id>jbrisbin</id>
|
||||||
<name>Jon Brisbin</name>
|
<name>Jon Brisbin</name>
|
||||||
<email>jbrisbin at vmware.com</email>
|
<email>jbrisbin at gopivotal.com</email>
|
||||||
<organization>SpringSource</organization>
|
<organization>Pivotal</organization>
|
||||||
<organizationUrl>http://www.springsource.com</organizationUrl>
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
<roles>
|
<roles>
|
||||||
<role>Developer</role>
|
<role>Developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
<timezone>-6</timezone>
|
<timezone>-6</timezone>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>tdarimont</id>
|
||||||
|
<name>Thomas Darimont</name>
|
||||||
|
<email>tdarimont at gopivotal.com</email>
|
||||||
|
<organization>Pivotal</organization>
|
||||||
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
|
<roles>
|
||||||
|
<role>Developer</role>
|
||||||
|
</roles>
|
||||||
|
<timezone>+1</timezone>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>cstrobl</id>
|
||||||
|
<name>Christoph Strobl</name>
|
||||||
|
<email>cstrobl at gopivotal.com</email>
|
||||||
|
<organization>Pivotal</organization>
|
||||||
|
<organizationUrl>http://www.gopivotal.com</organizationUrl>
|
||||||
|
<roles>
|
||||||
|
<role>Developer</role>
|
||||||
|
</roles>
|
||||||
|
<timezone>+1</timezone>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>mongo-next</id>
|
||||||
|
<properties>
|
||||||
|
<mongo>2.12.0-rc0</mongo>
|
||||||
|
<mongo-osgi>2.12.0</mongo-osgi>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- MongoDB -->
|
<!-- MongoDB -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -91,9 +124,16 @@
|
|||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-lib-milestone</id>
|
<id>spring-libs-milestone</id>
|
||||||
<url>http://repo.springsource.org/libs-milestone-local</url>
|
<url>http://repo.spring.io/libs-milestone/</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-plugins-release</id>
|
||||||
|
<url>http://repo.spring.io/plugins-release</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
<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.3.0.RC1</version>
|
<version>1.5.0.M1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-data-mongodb-cross-store</artifactId>
|
<artifactId>spring-data-mongodb-cross-store</artifactId>
|
||||||
<name>Spring Data MongoDB - Cross-Store Persistence Support</name>
|
<name>Spring Data MongoDB - Cross-Store Support</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<jpa>1.0.0.Final</jpa>
|
<jpa>1.0.0.Final</jpa>
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-beans</artifactId>
|
<artifactId>spring-beans</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
@@ -35,24 +34,21 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-tx</artifactId>
|
<artifactId>spring-tx</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-aspects</artifactId>
|
<artifactId>spring-aspects</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-orm</artifactId>
|
<artifactId>spring-orm</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Data -->
|
<!-- Spring Data -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>1.3.0.RC1</version>
|
<version>1.5.0.M1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -41,17 +41,13 @@ import com.mongodb.MongoException;
|
|||||||
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||||
|
|
||||||
private static final String ENTITY_CLASS = "_entity_class";
|
private static final String ENTITY_CLASS = "_entity_class";
|
||||||
|
|
||||||
private static final String ENTITY_ID = "_entity_id";
|
private static final String ENTITY_ID = "_entity_id";
|
||||||
|
|
||||||
private static final String ENTITY_FIELD_NAME = "_entity_field_name";
|
private static final String ENTITY_FIELD_NAME = "_entity_field_name";
|
||||||
|
|
||||||
private static final String ENTITY_FIELD_CLASS = "_entity_field_class";
|
private static final String ENTITY_FIELD_CLASS = "_entity_field_class";
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private MongoTemplate mongoTemplate;
|
private MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
private EntityManagerFactory entityManagerFactory;
|
private EntityManagerFactory entityManagerFactory;
|
||||||
|
|
||||||
public void setMongoTemplate(MongoTemplate mongoTemplate) {
|
public void setMongoTemplate(MongoTemplate mongoTemplate) {
|
||||||
@@ -113,12 +109,14 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
|||||||
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||||
*/
|
*/
|
||||||
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||||
|
|
||||||
log.debug("getPersistentId called on " + entity);
|
log.debug("getPersistentId called on " + entity);
|
||||||
|
|
||||||
if (entityManagerFactory == null) {
|
if (entityManagerFactory == null) {
|
||||||
throw new DataAccessResourceFailureException("EntityManagerFactory cannot be null");
|
throw new DataAccessResourceFailureException("EntityManagerFactory cannot be null");
|
||||||
}
|
}
|
||||||
Object o = entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);
|
|
||||||
return o;
|
return entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
Bundle-SymbolicName: org.springframework.data.mongodb.crossstore
|
Bundle-SymbolicName: org.springframework.data.mongodb.crossstore
|
||||||
Bundle-Name: Spring Data MongoDB Cross Store Support
|
Bundle-Name: Spring Data MongoDB Cross Store Support
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: Pivotal Software, Inc.
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Import-Package:
|
Import-Package:
|
||||||
sun.reflect;version="0";resolution:=optional
|
sun.reflect;version="0";resolution:=optional
|
||||||
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="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",
|
||||||
org.slf4j.*;version="${slf4j:[=.=.=,+1.0.0)}",
|
org.slf4j.*;version="${slf4j:[=.=.=,+1.0.0)}",
|
||||||
org.springframework.*;version="${spring30:[=.=.=.=,+1.0.0)}",
|
org.springframework.*;version="${spring:[=.=.=.=,+1.0.0)}",
|
||||||
org.springframework.data.*;version="${springdata.commons:[=.=.=.=,+1.0.0)}",
|
org.springframework.data.*;version="${springdata.commons:[=.=.=.=,+1.0.0)}",
|
||||||
org.springframework.data.mongodb.*;version="${project.version:[=.=.=.=,+1.0.0)}",
|
org.springframework.data.mongodb.*;version="${project.version:[=.=.=.=,+1.0.0)}",
|
||||||
org.w3c.dom.*;version="0"
|
org.w3c.dom.*;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.3.0.RC1</version>
|
<version>1.5.0.M1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -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.3.0.RC1</version>
|
<version>1.5.0.M1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
Bundle-SymbolicName: org.springframework.data.mongodb.log4j
|
Bundle-SymbolicName: org.springframework.data.mongodb.log4j
|
||||||
Bundle-Name: Spring Data Mongo DB Log4J Appender
|
Bundle-Name: Spring Data Mongo DB Log4J Appender
|
||||||
Bundle-Vendor: SpringSource
|
Bundle-Vendor: Pivotal Software, Inc.
|
||||||
Bundle-ManifestVersion: 2
|
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:[=.=,+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,153 +1,182 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<context version="7.1.7.187">
|
<context version="7.1.9.205">
|
||||||
<scope name="spring-data-mongodb" type="Project">
|
<scope type="Project" name="spring-data-mongodb">
|
||||||
<element name="Filter" type="TypeFilterReferenceOverridden">
|
<element type="TypeFilterReferenceOverridden" name="Filter">
|
||||||
<element name="org.springframework.data.mongodb.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.**"/>
|
||||||
</element>
|
</element>
|
||||||
<architecture>
|
<architecture>
|
||||||
<element name="Config" type="Layer">
|
<element type="Layer" name="Repositories">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.config.**" type="WeakTypePattern"/>
|
<element type="IncludeTypePattern" name="**.repository.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
|
<element type="Subsystem" name="API">
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|GridFS"/>
|
<element type="TypeFilter" name="Assignment">
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Monitoring"/>
|
<element type="IncludeTypePattern" name="**.repository.*"/>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories"/>
|
</element>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Query">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="IncludeTypePattern" name="**.query.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Implementation">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="IncludeTypePattern" name="**.support.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Query" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Config">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="IncludeTypePattern" name="**.config.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Config" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="Repositories" type="Layer">
|
<element type="Layer" name="Config">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.repository.**" type="IncludeTypePattern"/>
|
<element type="WeakTypePattern" name="**.config.**"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="API" type="Subsystem">
|
<dependency toName="Project|spring-data-mongodb::Layer|Core" type="AllowedDependency"/>
|
||||||
<element name="Assignment" type="TypeFilter">
|
<dependency toName="Project|spring-data-mongodb::Layer|GridFS" type="AllowedDependency"/>
|
||||||
<element name="**.repository.*" type="IncludeTypePattern"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Monitoring" type="AllowedDependency"/>
|
||||||
</element>
|
|
||||||
</element>
|
|
||||||
<element name="Query" type="Subsystem">
|
|
||||||
<element name="Assignment" type="TypeFilter">
|
|
||||||
<element name="**.query.**" type="IncludeTypePattern"/>
|
|
||||||
</element>
|
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API"/>
|
|
||||||
</element>
|
|
||||||
<element name="Implementation" type="Subsystem">
|
|
||||||
<element name="Assignment" type="TypeFilter">
|
|
||||||
<element name="**.support.**" type="IncludeTypePattern"/>
|
|
||||||
</element>
|
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API"/>
|
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Query"/>
|
|
||||||
</element>
|
|
||||||
<element name="Config" type="Subsystem">
|
|
||||||
<element name="Assignment" type="TypeFilter">
|
|
||||||
<element name="**.config.**" type="IncludeTypePattern"/>
|
|
||||||
</element>
|
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation"/>
|
|
||||||
</element>
|
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
|
|
||||||
</element>
|
</element>
|
||||||
<element name="Monitoring" type="Layer">
|
<element type="Layer" name="Monitoring">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.monitor.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**.monitor.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="GridFS" type="Layer">
|
<element type="Layer" name="GridFS">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.gridfs.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**.gridfs.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="Core" type="Layer">
|
<element type="Layer" name="Core">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment"/>
|
||||||
<element name="**.core.**" type="IncludeTypePattern"/>
|
<element type="Subsystem" name="Mapping">
|
||||||
</element>
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="Mapping" type="Subsystem">
|
<element type="IncludeTypePattern" name="**.core.mapping.**"/>
|
||||||
<element name="Assignment" type="TypeFilter">
|
|
||||||
<element name="**.mapping.**" type="IncludeTypePattern"/>
|
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element name="Geospatial" type="Subsystem">
|
<element type="Subsystem" name="Geospatial">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.geo.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**.core.geo.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
|
|
||||||
</element>
|
</element>
|
||||||
<element name="Query" type="Subsystem">
|
<element type="Subsystem" name="Query">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.query.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**.core.query.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="Index" type="Subsystem">
|
<element type="Subsystem" name="Conversion">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.index.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**.core.convert.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query"/>
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="Core" type="Subsystem">
|
<element type="Subsystem" name="SpEL">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="**.core.**" type="WeakTypePattern"/>
|
<element type="IncludeTypePattern" name="**.core.spel.**"/>
|
||||||
</element>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial"/>
|
</element>
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Index"/>
|
<element type="Subsystem" name="Aggregation">
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
|
<element type="TypeFilter" name="Assignment">
|
||||||
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query"/>
|
<element type="IncludeTypePattern" name="**.core.aggregation.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Conversion" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|SpEL" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Index">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="IncludeTypePattern" name="**.core.index.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Core">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="WeakTypePattern" name="**.core.**"/>
|
||||||
|
</element>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Aggregation" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Conversion" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Index" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||||
|
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
|
||||||
|
</element>
|
||||||
|
<element type="Subsystem" name="Util">
|
||||||
|
<element type="TypeFilter" name="Assignment">
|
||||||
|
<element type="IncludeTypePattern" name="**.util.**"/>
|
||||||
|
</element>
|
||||||
|
<stereotype name="Unrestricted"/>
|
||||||
|
<stereotype name="Public"/>
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element name="API" type="Subsystem">
|
<element type="Subsystem" name="API">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="org.springframework.data.mongodb.*" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.*"/>
|
||||||
</element>
|
</element>
|
||||||
<stereotype name="Public"/>
|
<stereotype name="Public"/>
|
||||||
</element>
|
</element>
|
||||||
</architecture>
|
</architecture>
|
||||||
<workspace>
|
<workspace>
|
||||||
<element name="src/main/java" type="JavaRootDirectory">
|
<element type="JavaRootDirectory" name="src/main/java">
|
||||||
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
|
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
|
||||||
</element>
|
</element>
|
||||||
<element name="target/classes" type="JavaRootDirectory">
|
<element type="JavaRootDirectory" name="target/classes">
|
||||||
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
|
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
|
||||||
</element>
|
</element>
|
||||||
</workspace>
|
</workspace>
|
||||||
<physical>
|
<physical>
|
||||||
<element name="spring-data-mongodb" type="BuildUnit"/>
|
<element type="BuildUnit" name="spring-data-mongodb"/>
|
||||||
</physical>
|
</physical>
|
||||||
</scope>
|
</scope>
|
||||||
<scope name="External" type="External">
|
<scope type="External" name="External">
|
||||||
<element name="Filter" type="TypeFilter">
|
<element type="TypeFilter" name="Filter">
|
||||||
<element name="**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**"/>
|
||||||
<element name="java.**" type="ExcludeTypePattern"/>
|
<element type="ExcludeTypePattern" name="java.**"/>
|
||||||
<element name="javax.**" type="ExcludeTypePattern"/>
|
<element type="ExcludeTypePattern" name="javax.**"/>
|
||||||
</element>
|
</element>
|
||||||
<architecture>
|
<architecture>
|
||||||
<element name="Spring" type="Subsystem">
|
<element type="Subsystem" name="Spring">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="org.springframework.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="org.springframework.**"/>
|
||||||
<element name="org.springframework.data.**" type="ExcludeTypePattern"/>
|
<element type="ExcludeTypePattern" name="org.springframework.data.**"/>
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element name="Spring Data Core" type="Subsystem">
|
<element type="Subsystem" name="Spring Data Core">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="org.springframework.data.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="org.springframework.data.**"/>
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element name="Mongo Java Driver" type="Subsystem">
|
<element type="Subsystem" name="Mongo Java Driver">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="com.mongodb.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="com.mongodb.**"/>
|
||||||
<element name="org.bson.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="org.bson.**"/>
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element name="Querydsl" type="Subsystem">
|
<element type="Subsystem" name="Querydsl">
|
||||||
<element name="Assignment" type="TypeFilter">
|
<element type="TypeFilter" name="Assignment">
|
||||||
<element name="com.mysema.query.**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="com.mysema.query.**"/>
|
||||||
</element>
|
</element>
|
||||||
</element>
|
</element>
|
||||||
</architecture>
|
</architecture>
|
||||||
</scope>
|
</scope>
|
||||||
<scope name="Global" type="Global">
|
<scope type="Global" name="Global">
|
||||||
<element name="Configuration" type="Configuration"/>
|
<element type="Configuration" name="Configuration"/>
|
||||||
<element name="Filter" type="TypeFilter">
|
<element type="TypeFilter" name="Filter">
|
||||||
<element name="**" type="IncludeTypePattern"/>
|
<element type="IncludeTypePattern" name="**"/>
|
||||||
</element>
|
</element>
|
||||||
</scope>
|
</scope>
|
||||||
</context>
|
</context>
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
<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.3.0.RC1</version>
|
<version>1.5.0.M1</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>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -25,22 +26,18 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-tx</artifactId>
|
<artifactId>spring-tx</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-beans</artifactId>
|
<artifactId>spring-beans</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-core</artifactId>
|
<artifactId>spring-core</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
@@ -51,11 +48,10 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-expression</artifactId>
|
<artifactId>spring-expression</artifactId>
|
||||||
<version>${spring}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Data -->
|
<!-- Spring Data -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>spring-data-commons</artifactId>
|
<artifactId>spring-data-commons</artifactId>
|
||||||
<version>${springdata.commons}</version>
|
<version>${springdata.commons}</version>
|
||||||
@@ -119,6 +115,13 @@
|
|||||||
<version>${validation}</version>
|
<version>${validation}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.objenesis</groupId>
|
||||||
|
<artifactId>objenesis</artifactId>
|
||||||
|
<version>${objenesis}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
@@ -134,6 +137,13 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jul-to-slf4j</artifactId>
|
||||||
|
<version>${slf4j}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -142,7 +152,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.mysema.maven</groupId>
|
<groupId>com.mysema.maven</groupId>
|
||||||
<artifactId>apt-maven-plugin</artifactId>
|
<artifactId>apt-maven-plugin</artifactId>
|
||||||
<version>1.0.8</version>
|
<version>${apt}</version>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysema.querydsl</groupId>
|
<groupId>com.mysema.querydsl</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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;
|
||||||
|
|
||||||
|
import org.springframework.dao.UncategorizedDataAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class LazyLoadingException extends UncategorizedDataAccessException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7089224903873220037L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param msg
|
||||||
|
* @param cause
|
||||||
|
*/
|
||||||
|
public LazyLoadingException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2013 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;
|
package org.springframework.data.mongodb;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
|
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
|
|
||||||
@@ -8,6 +25,7 @@ import com.mongodb.DB;
|
|||||||
* Interface for factories creating {@link DB} instances.
|
* Interface for factories creating {@link DB} instances.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public interface MongoDbFactory {
|
public interface MongoDbFactory {
|
||||||
|
|
||||||
@@ -27,4 +45,11 @@ public interface MongoDbFactory {
|
|||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
DB getDb(String dbName) throws DataAccessException;
|
DB getDb(String dbName) throws DataAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes a shared {@link MongoExceptionTranslator}.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
PersistenceExceptionTranslator getExceptionTranslator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,12 @@ 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.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;
|
||||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
@@ -47,6 +50,7 @@ import com.mongodb.Mongo;
|
|||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public abstract class AbstractMongoConfiguration {
|
public abstract class AbstractMongoConfiguration {
|
||||||
@@ -58,6 +62,16 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
*/
|
*/
|
||||||
protected abstract String getDatabaseName();
|
protected abstract String getDatabaseName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the authentication database to use. Defaults to {@literal null} and will turn into the value
|
||||||
|
* returned by {@link #getDatabaseName()} later on effectively.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String getAuthenticationDatabaseName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link Mongo} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
* Return the {@link Mongo} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
||||||
* {@link Mongo} instance to the {@link org.springframework.context.ApplicationContext}.
|
* {@link Mongo} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||||
@@ -88,15 +102,8 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public SimpleMongoDbFactory mongoDbFactory() throws Exception {
|
public MongoDbFactory mongoDbFactory() throws Exception {
|
||||||
|
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials(), getAuthenticationDatabaseName());
|
||||||
UserCredentials credentials = getUserCredentials();
|
|
||||||
|
|
||||||
if (credentials == null) {
|
|
||||||
return new SimpleMongoDbFactory(mongo(), getDatabaseName());
|
|
||||||
} else {
|
|
||||||
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), credentials);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +116,9 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
* entities.
|
* entities.
|
||||||
*/
|
*/
|
||||||
protected String getMappingBasePackage() {
|
protected String getMappingBasePackage() {
|
||||||
return getClass().getPackage().getName();
|
|
||||||
|
Package mappingBasePackage = getClass().getPackage();
|
||||||
|
return mappingBasePackage == null ? null : mappingBasePackage.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,8 +187,11 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MappingMongoConverter mappingMongoConverter() throws Exception {
|
public MappingMongoConverter mappingMongoConverter() throws Exception {
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), mongoMappingContext());
|
|
||||||
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
||||||
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions());
|
converter.setCustomConversions(customConversions());
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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,13 +24,14 @@ package org.springframework.data.mongodb.config;
|
|||||||
*/
|
*/
|
||||||
public abstract class BeanNames {
|
public abstract class BeanNames {
|
||||||
|
|
||||||
static final String MAPPING_CONTEXT = "mappingContext";
|
public static final String MAPPING_CONTEXT_BEAN_NAME = "mongoMappingContext";
|
||||||
static final String INDEX_HELPER = "indexCreationHelper";
|
|
||||||
static final String MONGO = "mongo";
|
static final String INDEX_HELPER_BEAN_NAME = "indexCreationHelper";
|
||||||
static final String DB_FACTORY = "mongoDbFactory";
|
static final String MONGO_BEAN_NAME = "mongo";
|
||||||
static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener";
|
static final String DB_FACTORY_BEAN_NAME = "mongoDbFactory";
|
||||||
static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory";
|
static final String VALIDATING_EVENT_LISTENER_BEAN_NAME = "validatingMongoEventListener";
|
||||||
|
static final String IS_NEW_STRATEGY_FACTORY_BEAN_NAME = "isNewStrategyFactory";
|
||||||
static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter";
|
static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter";
|
||||||
static final String MONGO_TEMPLATE = "mongoTemplate";
|
static final String MONGO_TEMPLATE_BEAN_NAME = "mongoTemplate";
|
||||||
static final String GRID_FS_TEMPLATE = "gridFsTemplate";
|
static final String GRID_FS_TEMPLATE_BEAN_NAME = "gridFsTemplate";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.data.auditing.DateTimeProvider;
|
||||||
|
import org.springframework.data.domain.AuditorAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to enable auditing in MongoDB via annotation configuration.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import(MongoAuditingRegistrar.class)
|
||||||
|
public @interface EnableMongoAuditing {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link AuditorAware} bean to be used to lookup the current principal.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String auditorAwareRef() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean setDates() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal true}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean modifyOnCreate() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a {@link DateTimeProvider} bean name that allows customizing the {@link org.joda.time.DateTime} to be
|
||||||
|
* used for setting creation and modification dates.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String dateTimeProviderRef() default "";
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
@@ -43,7 +43,7 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
|
|
||||||
String id = super.resolveId(element, definition, parserContext);
|
String id = super.resolveId(element, definition, parserContext);
|
||||||
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE;
|
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -57,13 +57,14 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
|
|
||||||
String converterRef = element.getAttribute("converter-ref");
|
String converterRef = element.getAttribute("converter-ref");
|
||||||
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
||||||
|
String bucket = element.getAttribute("bucket");
|
||||||
|
|
||||||
BeanDefinitionBuilder gridFsTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(GridFsTemplate.class);
|
BeanDefinitionBuilder gridFsTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(GridFsTemplate.class);
|
||||||
|
|
||||||
if (StringUtils.hasText(dbFactoryRef)) {
|
if (StringUtils.hasText(dbFactoryRef)) {
|
||||||
gridFsTemplateBuilder.addConstructorArgReference(dbFactoryRef);
|
gridFsTemplateBuilder.addConstructorArgReference(dbFactoryRef);
|
||||||
} else {
|
} else {
|
||||||
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY);
|
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY_BEAN_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.hasText(converterRef)) {
|
if (StringUtils.hasText(converterRef)) {
|
||||||
@@ -72,7 +73,11 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DEFAULT_CONVERTER_BEAN_NAME);
|
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DEFAULT_CONVERTER_BEAN_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (AbstractBeanDefinition) helper.getComponentIdButFallback(gridFsTemplateBuilder, BeanNames.GRID_FS_TEMPLATE)
|
if (StringUtils.hasText(bucket)) {
|
||||||
|
gridFsTemplateBuilder.addConstructorArgValue(bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (AbstractBeanDefinition) helper.getComponentIdButFallback(gridFsTemplateBuilder, BeanNames.GRID_FS_TEMPLATE_BEAN_NAME)
|
||||||
.getBeanDefinition();
|
.getBeanDefinition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -70,11 +70,12 @@ import org.w3c.dom.Element;
|
|||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Maciej Walkowiak
|
* @author Maciej Walkowiak
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private static final String BASE_PACKAGE = "base-package";
|
private static final String BASE_PACKAGE = "base-package";
|
||||||
private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator",
|
private static final boolean JSR_303_PRESENT = ClassUtils.isPresent("javax.validation.Validator",
|
||||||
MappingMongoConverterParser.class.getClassLoader());
|
MappingMongoConverterParser.class.getClassLoader());
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -85,7 +86,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||||
|
|
||||||
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
||||||
id = StringUtils.hasText(id) ? id : "mappingConverter";
|
id = StringUtils.hasText(id) ? id : DEFAULT_CONVERTER_BEAN_NAME;
|
||||||
|
|
||||||
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
|
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
// Need a reference to a Mongo instance
|
// Need a reference to a Mongo instance
|
||||||
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
||||||
if (!StringUtils.hasText(dbFactoryRef)) {
|
if (!StringUtils.hasText(dbFactoryRef)) {
|
||||||
dbFactoryRef = DB_FACTORY;
|
dbFactoryRef = DB_FACTORY_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converter
|
// Converter
|
||||||
@@ -105,15 +106,20 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
converterBuilder.addConstructorArgReference(dbFactoryRef);
|
converterBuilder.addConstructorArgReference(dbFactoryRef);
|
||||||
converterBuilder.addConstructorArgReference(ctxRef);
|
converterBuilder.addConstructorArgReference(ctxRef);
|
||||||
|
|
||||||
|
String typeMapperRef = element.getAttribute("type-mapper-ref");
|
||||||
|
if (StringUtils.hasText(typeMapperRef)) {
|
||||||
|
converterBuilder.addPropertyReference("typeMapper", typeMapperRef);
|
||||||
|
}
|
||||||
|
|
||||||
if (conversionsDefinition != null) {
|
if (conversionsDefinition != null) {
|
||||||
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
|
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
registry.getBeanDefinition(INDEX_HELPER);
|
registry.getBeanDefinition(INDEX_HELPER_BEAN_NAME);
|
||||||
} catch (NoSuchBeanDefinitionException ignored) {
|
} catch (NoSuchBeanDefinitionException ignored) {
|
||||||
if (!StringUtils.hasText(dbFactoryRef)) {
|
if (!StringUtils.hasText(dbFactoryRef)) {
|
||||||
dbFactoryRef = DB_FACTORY;
|
dbFactoryRef = DB_FACTORY_BEAN_NAME;
|
||||||
}
|
}
|
||||||
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
|
||||||
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
|
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
|
||||||
@@ -122,14 +128,14 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
indexHelperBuilder.addDependsOn(ctxRef);
|
indexHelperBuilder.addDependsOn(ctxRef);
|
||||||
|
|
||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
||||||
INDEX_HELPER));
|
INDEX_HELPER_BEAN_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
|
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
|
||||||
|
|
||||||
if (validatingMongoEventListener != null) {
|
if (validatingMongoEventListener != null) {
|
||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
|
parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
|
||||||
VALIDATING_EVENT_LISTENER));
|
VALIDATING_EVENT_LISTENER_BEAN_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
|
parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
|
||||||
@@ -160,7 +166,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
|
|
||||||
private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) {
|
private RuntimeBeanReference getValidator(Object source, ParserContext parserContext) {
|
||||||
|
|
||||||
if (!jsr303Present) {
|
if (!JSR_303_PRESENT) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +180,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
return new RuntimeBeanReference(validatorName);
|
return new RuntimeBeanReference(validatorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
|
public static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
|
||||||
BeanDefinition conversionsDefinition, String converterId) {
|
BeanDefinition conversionsDefinition, String converterId) {
|
||||||
|
|
||||||
String ctxRef = element.getAttribute("mapping-context-ref");
|
String ctxRef = element.getAttribute("mapping-context-ref");
|
||||||
@@ -189,7 +195,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
|
||||||
.genericBeanDefinition(MongoMappingContext.class);
|
.genericBeanDefinition(MongoMappingContext.class);
|
||||||
|
|
||||||
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
|
Set<String> classesToAdd = getInititalEntityClasses(element);
|
||||||
|
|
||||||
if (classesToAdd != null) {
|
if (classesToAdd != null) {
|
||||||
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
|
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
|
||||||
}
|
}
|
||||||
@@ -208,7 +215,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
CamelCaseAbbreviatingFieldNamingStrategy.class));
|
CamelCaseAbbreviatingFieldNamingStrategy.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxRef = converterId + "." + MAPPING_CONTEXT;
|
ctxRef = converterId == null || DEFAULT_CONVERTER_BEAN_NAME.equals(converterId) ? MAPPING_CONTEXT_BEAN_NAME
|
||||||
|
: converterId + "." + MAPPING_CONTEXT_BEAN_NAME;
|
||||||
|
|
||||||
parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
|
parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
|
||||||
return ctxRef;
|
return ctxRef;
|
||||||
@@ -256,7 +264,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {
|
private static Set<String> getInititalEntityClasses(Element element) {
|
||||||
|
|
||||||
String basePackage = element.getAttribute(BASE_PACKAGE);
|
String basePackage = element.getAttribute(BASE_PACKAGE);
|
||||||
|
|
||||||
@@ -303,9 +311,10 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
|
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
|
||||||
|
|
||||||
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
|
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
|
||||||
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY));
|
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder,
|
||||||
|
IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
|
||||||
|
|
||||||
return IS_NEW_STRATEGY_FACTORY;
|
return IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 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.
|
||||||
@@ -15,14 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.config;
|
package org.springframework.data.mongodb.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import static org.springframework.data.config.ParsingUtils.*;
|
||||||
|
import static org.springframework.data.mongodb.config.BeanNames.*;
|
||||||
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||||
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.IsNewAwareAuditingHandlerBeanDefinitionParser;
|
import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,23 +63,24 @@ public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinit
|
|||||||
@Override
|
@Override
|
||||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||||
|
|
||||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
String mappingContextRef = element.getAttribute("mapping-context-ref");
|
||||||
|
|
||||||
if (!registry.containsBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY)) {
|
if (!StringUtils.hasText(mappingContextRef)) {
|
||||||
|
|
||||||
String mappingContextName = BeanNames.MAPPING_CONTEXT;
|
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||||
|
|
||||||
if (!registry.containsBeanDefinition(BeanNames.MAPPING_CONTEXT)) {
|
if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) {
|
||||||
mappingContextName = MappingMongoConverterParser.potentiallyCreateMappingContext(element, parserContext, null,
|
registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, new RootBeanDefinition(MongoMappingContext.class));
|
||||||
BeanNames.DEFAULT_CONVERTER_BEAN_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingMongoConverterParser.createIsNewStrategyFactoryBeanDefinition(mappingContextName, parserContext, element);
|
mappingContextRef = MAPPING_CONTEXT_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(BeanNames.IS_NEW_STRATEGY_FACTORY);
|
IsNewAwareAuditingHandlerBeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(
|
||||||
BeanDefinition handlerBeanDefinition = parser.parse(element, parserContext);
|
mappingContextRef);
|
||||||
|
parser.parse(element, parserContext);
|
||||||
|
|
||||||
builder.addConstructorArgValue(handlerBeanDefinition);
|
builder.addConstructorArgValue(getObjectFactoryBeanDefinition(parser.getResolvedBeanName(),
|
||||||
|
parserContext.extractSource(element)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* 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.config;
|
||||||
|
|
||||||
|
import static org.springframework.beans.factory.config.BeanDefinition.*;
|
||||||
|
import static org.springframework.data.mongodb.config.BeanNames.*;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||||
|
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
||||||
|
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||||
|
import org.springframework.data.config.ParsingUtils;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||||
|
import org.springframework.data.support.IsNewStrategyFactory;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMongoAuditing} annotation.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Class<? extends Annotation> getAnnotation() {
|
||||||
|
return EnableMongoAuditing.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAuditingHandlerBeanName() {
|
||||||
|
return "mongoAuditingHandler";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
|
||||||
|
|
||||||
|
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
|
||||||
|
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||||
|
|
||||||
|
defaultDependenciesIfNecessary(registry, annotationMetadata);
|
||||||
|
super.registerBeanDefinitions(annotationMetadata, registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
|
||||||
|
|
||||||
|
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
|
||||||
|
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
|
||||||
|
builder.addConstructorArgReference(MAPPING_CONTEXT_BEAN_NAME);
|
||||||
|
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerAuditListener(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
|
||||||
|
BeanDefinitionRegistry registry) {
|
||||||
|
|
||||||
|
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
|
||||||
|
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||||
|
|
||||||
|
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(AuditingEventListener.class);
|
||||||
|
listenerBeanDefinitionBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(
|
||||||
|
getAuditingHandlerBeanName(), registry));
|
||||||
|
|
||||||
|
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
||||||
|
AuditingEventListener.class.getName(), registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register default bean definitions for a {@link MongoMappingContext} and an {@link IsNewStrategyFactory} in case we
|
||||||
|
* don't find beans with the assumed names in the registry.
|
||||||
|
*
|
||||||
|
* @param registry the {@link BeanDefinitionRegistry} to use to register the components into.
|
||||||
|
* @param source the source which the registered components shall be registered with
|
||||||
|
*/
|
||||||
|
private void defaultDependenciesIfNecessary(BeanDefinitionRegistry registry, Object source) {
|
||||||
|
|
||||||
|
if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) {
|
||||||
|
|
||||||
|
RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class);
|
||||||
|
definition.setRole(ROLE_INFRASTRUCTURE);
|
||||||
|
definition.setSource(source);
|
||||||
|
|
||||||
|
registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 by the original author(s).
|
* Copyright 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.
|
||||||
@@ -41,6 +41,7 @@ import com.mongodb.MongoURI;
|
|||||||
*
|
*
|
||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
|
|
||||||
String id = super.resolveId(element, definition, parserContext);
|
String id = super.resolveId(element, definition, parserContext);
|
||||||
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY;
|
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -70,6 +71,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
String uri = element.getAttribute("uri");
|
String uri = element.getAttribute("uri");
|
||||||
String mongoRef = element.getAttribute("mongo-ref");
|
String mongoRef = element.getAttribute("mongo-ref");
|
||||||
String dbname = element.getAttribute("dbname");
|
String dbname = element.getAttribute("dbname");
|
||||||
|
|
||||||
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
|
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
|
||||||
|
|
||||||
// Common setup
|
// Common setup
|
||||||
@@ -92,19 +94,16 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
dbFactoryBuilder.addConstructorArgValue(registerMongoBeanDefinition(element, parserContext));
|
dbFactoryBuilder.addConstructorArgValue(registerMongoBeanDefinition(element, parserContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
dbname = StringUtils.hasText(dbname) ? dbname : "db";
|
dbFactoryBuilder.addConstructorArgValue(StringUtils.hasText(dbname) ? dbname : "db");
|
||||||
dbFactoryBuilder.addConstructorArgValue(dbname);
|
dbFactoryBuilder.addConstructorArgValue(userCredentials);
|
||||||
|
dbFactoryBuilder.addConstructorArgValue(element.getAttribute("authentication-dbname"));
|
||||||
if (userCredentials != null) {
|
|
||||||
dbFactoryBuilder.addConstructorArgValue(userCredentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
|
BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
|
||||||
|
|
||||||
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
|
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
|
||||||
parserContext.registerBeanComponent(component);
|
parserContext.registerBeanComponent(component);
|
||||||
|
|
||||||
return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY)
|
return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY_BEAN_NAME)
|
||||||
.getBeanDefinition();
|
.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -16,9 +16,6 @@
|
|||||||
package org.springframework.data.mongodb.config;
|
package org.springframework.data.mongodb.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||||
import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension;
|
|
||||||
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
|
|
||||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB configuration.
|
* {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB configuration.
|
||||||
@@ -34,10 +31,6 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
|||||||
*/
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
RepositoryConfigurationExtension extension = new MongoRepositoryConfigurationExtension();
|
|
||||||
RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension);
|
|
||||||
|
|
||||||
registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser);
|
|
||||||
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
||||||
registerBeanDefinitionParser("mongo", new MongoParser());
|
registerBeanDefinitionParser("mongo", new MongoParser());
|
||||||
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -58,7 +58,7 @@ public class MongoParser implements BeanDefinitionParser {
|
|||||||
MongoParsingUtils.parseMongoOptions(element, builder);
|
MongoParsingUtils.parseMongoOptions(element, builder);
|
||||||
MongoParsingUtils.parseReplicaSet(element, builder);
|
MongoParsingUtils.parseReplicaSet(element, builder);
|
||||||
|
|
||||||
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO;
|
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
||||||
|
|
||||||
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
|
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 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.
|
||||||
@@ -33,6 +33,7 @@ import org.w3c.dom.Element;
|
|||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
abstract class MongoParsingUtils {
|
abstract class MongoParsingUtils {
|
||||||
|
|
||||||
@@ -79,6 +80,8 @@ abstract class MongoParsingUtils {
|
|||||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
|
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
|
||||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
|
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
|
||||||
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
|
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
|
||||||
|
setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||||
|
setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||||
|
|
||||||
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
|
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -35,6 +35,7 @@ import org.w3c.dom.Element;
|
|||||||
* {@link BeanDefinitionParser} to parse {@code template} elements into {@link BeanDefinition}s.
|
* {@link BeanDefinitionParser} to parse {@code template} elements into {@link BeanDefinition}s.
|
||||||
*
|
*
|
||||||
* @author Martin Baumgartner
|
* @author Martin Baumgartner
|
||||||
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
|
|
||||||
String id = super.resolveId(element, definition, parserContext);
|
String id = super.resolveId(element, definition, parserContext);
|
||||||
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE;
|
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -68,7 +69,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
if (StringUtils.hasText(dbFactoryRef)) {
|
if (StringUtils.hasText(dbFactoryRef)) {
|
||||||
mongoTemplateBuilder.addConstructorArgReference(dbFactoryRef);
|
mongoTemplateBuilder.addConstructorArgReference(dbFactoryRef);
|
||||||
} else {
|
} else {
|
||||||
mongoTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY);
|
mongoTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY_BEAN_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.hasText(converterRef)) {
|
if (StringUtils.hasText(converterRef)) {
|
||||||
@@ -80,7 +81,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
|
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
|
||||||
parserContext.registerBeanComponent(component);
|
parserContext.registerBeanComponent(component);
|
||||||
|
|
||||||
return (AbstractBeanDefinition) helper.getComponentIdButFallback(mongoTemplateBuilder, BeanNames.MONGO_TEMPLATE)
|
return (AbstractBeanDefinition) helper.getComponentIdButFallback(mongoTemplateBuilder,
|
||||||
.getBeanDefinition();
|
BeanNames.MONGO_TEMPLATE_BEAN_NAME).getBeanDefinition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,14 @@
|
|||||||
package org.springframework.data.mongodb.config;
|
package org.springframework.data.mongodb.config;
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
import java.beans.PropertyEditorSupport;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.ServerAddress;
|
import com.mongodb.ServerAddress;
|
||||||
@@ -35,6 +37,11 @@ import com.mongodb.ServerAddress;
|
|||||||
*/
|
*/
|
||||||
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A port is a number without a leading 0 at the end of the address that is proceeded by just a single :.
|
||||||
|
*/
|
||||||
|
private static final String HOST_PORT_SPLIT_PATTERN = "(?<!:):(?=[123456789]\\d*$)";
|
||||||
|
private static final String COULD_NOT_PARSE_ADDRESS_MESSAGE = "Could not parse address {} '{}'. Check your replica set configuration!";
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ServerAddressPropertyEditor.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ServerAddressPropertyEditor.class);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,22 +84,53 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
|||||||
*/
|
*/
|
||||||
private ServerAddress parseServerAddress(String source) {
|
private ServerAddress parseServerAddress(String source) {
|
||||||
|
|
||||||
String[] hostAndPort = StringUtils.delimitedListToStringArray(source.trim(), ":");
|
if (!StringUtils.hasText(source)) {
|
||||||
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!StringUtils.hasText(source) || hostAndPort.length > 2) {
|
String[] hostAndPort = extractHostAddressAndPort(source.trim());
|
||||||
LOG.warn("Could not parse address source '{}'. Check your replica set configuration!", source);
|
|
||||||
|
if (hostAndPort.length > 2) {
|
||||||
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return hostAndPort.length == 1 ? new ServerAddress(hostAndPort[0]) : new ServerAddress(hostAndPort[0],
|
InetAddress hostAddress = InetAddress.getByName(hostAndPort[0]);
|
||||||
Integer.parseInt(hostAndPort[1]));
|
Integer port = hostAndPort.length == 1 ? null : Integer.parseInt(hostAndPort[1]);
|
||||||
|
|
||||||
|
return port == null ? new ServerAddress(hostAddress) : new ServerAddress(hostAddress, port);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
LOG.warn("Could not parse host '{}'. Check your replica set configuration!", hostAndPort[0]);
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "host", hostAndPort[0]);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
LOG.warn("Could not parse port '{}'. Check your replica set configuration!", hostAndPort[1]);
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "port", hostAndPort[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the host and port from the given {@link String}.
|
||||||
|
*
|
||||||
|
* @param addressAndPortSource must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String[] extractHostAddressAndPort(String addressAndPortSource) {
|
||||||
|
|
||||||
|
Assert.notNull(addressAndPortSource, "Address and port source must not be null!");
|
||||||
|
|
||||||
|
String[] hostAndPort = addressAndPortSource.split(HOST_PORT_SPLIT_PATTERN);
|
||||||
|
String hostAddress = hostAndPort[0];
|
||||||
|
|
||||||
|
if (isHostAddressInIPv6BracketNotation(hostAddress)) {
|
||||||
|
hostAndPort[0] = hostAddress.substring(1, hostAddress.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostAndPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHostAddressInIPv6BracketNotation(String hostAddress) {
|
||||||
|
return hostAddress.startsWith("[") && hostAddress.endsWith("]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import static org.springframework.data.domain.Sort.Direction.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -22,7 +24,6 @@ import org.springframework.dao.DataAccessException;
|
|||||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||||
import org.springframework.data.mongodb.core.index.IndexField;
|
import org.springframework.data.mongodb.core.index.IndexField;
|
||||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||||
import org.springframework.data.mongodb.core.query.Order;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
@@ -34,9 +35,13 @@ import com.mongodb.MongoException;
|
|||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Komi Innocent
|
||||||
*/
|
*/
|
||||||
public class DefaultIndexOperations implements IndexOperations {
|
public class DefaultIndexOperations implements IndexOperations {
|
||||||
|
|
||||||
|
private static final Double ONE = Double.valueOf(1);
|
||||||
|
private static final Double MINUS_ONE = Double.valueOf(-1);
|
||||||
|
|
||||||
private final MongoOperations mongoOperations;
|
private final MongoOperations mongoOperations;
|
||||||
private final String collectionName;
|
private final String collectionName;
|
||||||
|
|
||||||
@@ -135,12 +140,17 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
|
|
||||||
Object value = keyDbObject.get(key);
|
Object value = keyDbObject.get(key);
|
||||||
|
|
||||||
if (Integer.valueOf(1).equals(value)) {
|
if ("2d".equals(value)) {
|
||||||
indexFields.add(IndexField.create(key, Order.ASCENDING));
|
|
||||||
} else if (Integer.valueOf(-1).equals(value)) {
|
|
||||||
indexFields.add(IndexField.create(key, Order.DESCENDING));
|
|
||||||
} else if ("2d".equals(value)) {
|
|
||||||
indexFields.add(IndexField.geo(key));
|
indexFields.add(IndexField.geo(key));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Double keyValue = new Double(value.toString());
|
||||||
|
|
||||||
|
if (ONE.equals(keyValue)) {
|
||||||
|
indexFields.add(IndexField.create(key, ASC));
|
||||||
|
} else if (MINUS_ONE.equals(keyValue)) {
|
||||||
|
indexFields.add(IndexField.create(key, DESC));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 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.Mongo;
|
|||||||
* Mongo server administration exposed via JMX annotations
|
* Mongo server administration exposed via JMX annotations
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@ManagedResource(description = "Mongo Admin Operations")
|
@ManagedResource(description = "Mongo Admin Operations")
|
||||||
public class MongoAdmin implements MongoAdminOperations {
|
public class MongoAdmin implements MongoAdminOperations {
|
||||||
@@ -34,6 +35,7 @@ public class MongoAdmin implements MongoAdminOperations {
|
|||||||
private final Mongo mongo;
|
private final Mongo mongo;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String authenticationDatabaseName;
|
||||||
|
|
||||||
public MongoAdmin(Mongo mongo) {
|
public MongoAdmin(Mongo mongo) {
|
||||||
Assert.notNull(mongo);
|
Assert.notNull(mongo);
|
||||||
@@ -82,7 +84,16 @@ public class MongoAdmin implements MongoAdminOperations {
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
|
||||||
|
*
|
||||||
|
* @param authenticationDatabaseName The authenticationDatabaseName to use.
|
||||||
|
*/
|
||||||
|
public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
|
||||||
|
this.authenticationDatabaseName = authenticationDatabaseName;
|
||||||
|
}
|
||||||
|
|
||||||
DB getDB(String databaseName) {
|
DB getDB(String databaseName) {
|
||||||
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password));
|
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mark Pollack
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
public interface MongoAdminOperations {
|
public interface MongoAdminOperations {
|
||||||
|
|
||||||
@ManagedOperation
|
@ManagedOperation
|
||||||
public abstract void dropDatabase(String databaseName);
|
void dropDatabase(String databaseName);
|
||||||
|
|
||||||
@ManagedOperation
|
@ManagedOperation
|
||||||
public abstract void createDatabase(String databaseName);
|
void createDatabase(String databaseName);
|
||||||
|
|
||||||
@ManagedOperation
|
@ManagedOperation
|
||||||
public abstract String getDatabaseStats(String databaseName);
|
String getDatabaseStats(String databaseName);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 the original author or authors.
|
* Copyright 2010-2013 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,14 +26,14 @@ import com.mongodb.DB;
|
|||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class featuring helper methods for internal MongoDb classes.
|
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
||||||
* <p/>
|
* framework.
|
||||||
* <p>
|
|
||||||
* Mainly intended for internal use within the framework.
|
|
||||||
*
|
*
|
||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Randy Watler
|
||||||
|
* @author Thomas Darimont
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public abstract class MongoDbUtils {
|
public abstract class MongoDbUtils {
|
||||||
@@ -55,7 +55,7 @@ public abstract class MongoDbUtils {
|
|||||||
* @return the {@link DB} connection
|
* @return the {@link DB} connection
|
||||||
*/
|
*/
|
||||||
public static DB getDB(Mongo mongo, String databaseName) {
|
public static DB getDB(Mongo mongo, String databaseName) {
|
||||||
return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true);
|
return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true, databaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,15 +67,22 @@ public abstract class MongoDbUtils {
|
|||||||
* @return the {@link DB} connection
|
* @return the {@link DB} connection
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
|
String authenticationDatabaseName) {
|
||||||
|
|
||||||
Assert.notNull(mongo, "No Mongo instance specified!");
|
Assert.notNull(mongo, "No Mongo instance specified!");
|
||||||
Assert.hasText(databaseName, "Database name must be given!");
|
Assert.hasText(databaseName, "Database name must be given!");
|
||||||
Assert.notNull(credentials, "Credentials must not be null, use UserCredentials.NO_CREDENTIALS!");
|
Assert.notNull(credentials, "Credentials must not be null, use UserCredentials.NO_CREDENTIALS!");
|
||||||
|
Assert.hasText(authenticationDatabaseName, "Authentication database name must not be null or empty!");
|
||||||
|
|
||||||
return doGetDB(mongo, databaseName, credentials, true);
|
return doGetDB(mongo, databaseName, credentials, true, authenticationDatabaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate) {
|
private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate,
|
||||||
|
String authenticationDatabaseName) {
|
||||||
|
|
||||||
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
|
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
|
||||||
|
|
||||||
@@ -104,14 +111,16 @@ public abstract class MongoDbUtils {
|
|||||||
DB db = mongo.getDB(databaseName);
|
DB db = mongo.getDB(databaseName);
|
||||||
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
|
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
|
||||||
|
|
||||||
synchronized (db) {
|
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
||||||
|
|
||||||
if (credentialsGiven && !db.isAuthenticated()) {
|
synchronized (authDb) {
|
||||||
|
|
||||||
|
if (credentialsGiven && !authDb.isAuthenticated()) {
|
||||||
|
|
||||||
String username = credentials.getUsername();
|
String username = credentials.getUsername();
|
||||||
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
||||||
|
|
||||||
if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
|
if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
|
||||||
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
||||||
+ credentials.toString(), databaseName, credentials);
|
+ credentials.toString(), databaseName, credentials);
|
||||||
}
|
}
|
||||||
@@ -131,8 +140,11 @@ public abstract class MongoDbUtils {
|
|||||||
holderToUse.addDB(databaseName, db);
|
holderToUse.addDB(databaseName, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
|
// synchronize holder only if not yet synchronized
|
||||||
holderToUse.setSynchronizedWithTransaction(true);
|
if (!holderToUse.isSynchronizedWithTransaction()) {
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
|
||||||
|
holderToUse.setSynchronizedWithTransaction(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (holderToUse != dbHolder) {
|
if (holderToUse != dbHolder) {
|
||||||
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
|
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
|||||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
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) {
|
if (ex instanceof MongoInternalException) {
|
||||||
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
|
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2013 the original author or authors.
|
* Copyright 2011-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.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@@ -23,7 +23,6 @@ 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.GeoResult;
|
|
||||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
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;
|
||||||
@@ -49,7 +48,11 @@ import com.mongodb.WriteResult;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Tobias Trelle
|
* @author Tobias Trelle
|
||||||
|
* @author Chuong Ngo
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public interface MongoOperations {
|
public interface MongoOperations {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,7 +415,7 @@ public interface MongoOperations {
|
|||||||
MapReduceOptions mapReduceOptions, Class<T> entityClass);
|
MapReduceOptions mapReduceOptions, Class<T> entityClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link GeoResult} 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.
|
||||||
*
|
*
|
||||||
* @param near must not be {@literal null}.
|
* @param near must not be {@literal null}.
|
||||||
@@ -422,7 +425,7 @@ public interface MongoOperations {
|
|||||||
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
|
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link GeoResult} for all entities matching the given {@link NearQuery}.
|
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}.
|
||||||
*
|
*
|
||||||
* @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}.
|
||||||
@@ -467,10 +470,32 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
<T> T findOne(Query query, Class<T> entityClass, String collectionName);
|
<T> T findOne(Query query, Class<T> entityClass, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine result of given {@link Query} contains at least one element.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||||
|
* @param collectionName name of the collection to check for objects.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean exists(Query query, String collectionName);
|
boolean exists(Query query, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine result of given {@link Query} contains at least one element.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean exists(Query query, Class<?> entityClass);
|
boolean exists(Query query, Class<?> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine result of given {@link Query} contains at least one element.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @param collectionName name of the collection to check for objects.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean exists(Query query, Class<?> entityClass, String collectionName);
|
boolean exists(Query query, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -528,12 +553,58 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
<T> T findById(Object id, Class<T> entityClass, String collectionName);
|
<T> T findById(Object id, Class<T> entityClass, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
|
||||||
|
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||||
|
* fields specification.
|
||||||
|
* @param update the {@link Update} to apply on matching documents.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
<T> T findAndModify(Query query, Update update, Class<T> entityClass);
|
<T> T findAndModify(Query query, Update update, Class<T> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
|
||||||
|
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||||
|
* fields specification.
|
||||||
|
* @param update the {@link Update} to apply on matching documents.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @param collectionName the collection to query.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
|
<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
|
||||||
|
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||||
|
* {@link FindAndModifyOptions} into account.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||||
|
* fields specification.
|
||||||
|
* @param update the {@link Update} to apply on matching documents.
|
||||||
|
* @param options the {@link FindAndModifyOptions} holding additional information.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
|
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
|
||||||
|
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||||
|
* {@link FindAndModifyOptions} into account.
|
||||||
|
*
|
||||||
|
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||||
|
* fields specification.
|
||||||
|
* @param update the {@link Update} to apply on matching documents.
|
||||||
|
* @param options the {@link FindAndModifyOptions} holding additional information.
|
||||||
|
* @param entityClass the parameterized type.
|
||||||
|
* @param collectionName the collection to query.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
|
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
|
||||||
String collectionName);
|
String collectionName);
|
||||||
|
|
||||||
@@ -597,9 +668,9 @@ public interface MongoOperations {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
||||||
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
||||||
* property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's new Type Conversion API.
|
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
|
||||||
* See <a href="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">Spring 3 Type
|
* href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert"
|
||||||
* Conversion"</a> for more details.
|
* >Spring's Type Conversion"</a> for more details.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <p/>
|
* <p/>
|
||||||
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
||||||
@@ -654,9 +725,9 @@ public interface MongoOperations {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
||||||
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
||||||
* property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's new Type Conversion API.
|
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
|
||||||
* See <a href="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">Spring 3 Type
|
* href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert"
|
||||||
* Conversion"</a> for more details.
|
* >Spring's Type Conversion"</a> for more details.
|
||||||
*
|
*
|
||||||
* @param objectToSave the object to store in the collection
|
* @param objectToSave the object to store in the collection
|
||||||
*/
|
*/
|
||||||
@@ -671,9 +742,9 @@ public interface MongoOperations {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
||||||
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
||||||
* property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's new Type Cobnversion API.
|
* property type will be handled by Spring's BeanWrapper class that leverages Type Cobnversion API. See <a
|
||||||
* See <a href="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">Spring 3 Type
|
* http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert">Spring's
|
||||||
* Conversion"</a> for more details.
|
* Type Conversion"</a> for more details.
|
||||||
*
|
*
|
||||||
* @param objectToSave the object to store in the collection
|
* @param objectToSave the object to store in the collection
|
||||||
* @param collectionName name of the collection to store the object in
|
* @param collectionName name of the collection to store the object in
|
||||||
@@ -703,6 +774,18 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
WriteResult upsert(Query query, Update update, String collectionName);
|
WriteResult upsert(Query query, Update update, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
|
||||||
|
* combining the query document and the update document.
|
||||||
|
*
|
||||||
|
* @param query the query document that specifies the criteria used to select a record to be upserted
|
||||||
|
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
|
||||||
|
* @param entityClass class of the pojo to be operated on
|
||||||
|
* @param collectionName name of the collection to update the object in
|
||||||
|
* @return the WriteResult which lets you access the results of the previous write.
|
||||||
|
*/
|
||||||
|
WriteResult upsert(Query query, Update update, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the first object that is found in the collection of the entity class that matches the query document with
|
* Updates the first object that is found in the collection of the entity class that matches the query document with
|
||||||
* the provided update document.
|
* the provided update document.
|
||||||
@@ -727,6 +810,19 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
WriteResult updateFirst(Query query, Update update, String collectionName);
|
WriteResult updateFirst(Query query, Update update, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the first object that is found in the specified collection that matches the query document criteria with
|
||||||
|
* the provided updated document.
|
||||||
|
*
|
||||||
|
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||||
|
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||||
|
* object.
|
||||||
|
* @param entityClass class of the pojo to be operated on
|
||||||
|
* @param collectionName name of the collection to update the object in
|
||||||
|
* @return the WriteResult which lets you access the results of the previous write.
|
||||||
|
*/
|
||||||
|
WriteResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
|
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
|
||||||
* with the provided updated document.
|
* with the provided updated document.
|
||||||
@@ -751,12 +847,25 @@ public interface MongoOperations {
|
|||||||
*/
|
*/
|
||||||
WriteResult updateMulti(Query query, Update update, String collectionName);
|
WriteResult updateMulti(Query query, Update update, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
|
||||||
|
* with the provided updated document.
|
||||||
|
*
|
||||||
|
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||||
|
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||||
|
* object.
|
||||||
|
* @param entityClass class of the pojo to be operated on
|
||||||
|
* @param collectionName name of the collection to update the object in
|
||||||
|
* @return the WriteResult which lets you access the results of the previous write.
|
||||||
|
*/
|
||||||
|
WriteResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given object from the collection by id.
|
* Remove the given object from the collection by id.
|
||||||
*
|
*
|
||||||
* @param object
|
* @param object
|
||||||
*/
|
*/
|
||||||
void remove(Object object);
|
WriteResult remove(Object object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given object from the given collection.
|
* Removes the given object from the given collection.
|
||||||
@@ -764,7 +873,7 @@ public interface MongoOperations {
|
|||||||
* @param object
|
* @param object
|
||||||
* @param collection must not be {@literal null} or empty.
|
* @param collection must not be {@literal null} or empty.
|
||||||
*/
|
*/
|
||||||
void remove(Object object, String collection);
|
WriteResult remove(Object object, String collection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all documents that match the provided query document criteria from the the collection used to store the
|
* Remove all documents that match the provided query document criteria from the the collection used to store the
|
||||||
@@ -773,9 +882,17 @@ public interface MongoOperations {
|
|||||||
* @param query
|
* @param query
|
||||||
* @param entityClass
|
* @param entityClass
|
||||||
*/
|
*/
|
||||||
void remove(Query query, Class<?> entityClass);
|
WriteResult remove(Query query, Class<?> entityClass);
|
||||||
|
|
||||||
void remove(Query query, Class<?> entityClass, String collectionName);
|
/**
|
||||||
|
* Remove all documents that match the provided query document criteria from the the collection used to store the
|
||||||
|
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param entityClass
|
||||||
|
* @param collectionName
|
||||||
|
*/
|
||||||
|
WriteResult remove(Query query, Class<?> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all documents from the specified collection that match the provided query document criteria. There is no
|
* Remove all documents from the specified collection that match the provided query document criteria. There is no
|
||||||
@@ -784,7 +901,40 @@ public interface MongoOperations {
|
|||||||
* @param query the query document that specifies the criteria used to remove a record
|
* @param query the query document that specifies the criteria used to remove a record
|
||||||
* @param collectionName name of the collection where the objects will removed
|
* @param collectionName name of the collection where the objects will removed
|
||||||
*/
|
*/
|
||||||
void remove(Query query, String collectionName);
|
WriteResult remove(Query query, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns and removes all documents form the specified collection that match the provided query.
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param collectionName
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
<T> List<T> findAllAndRemove(Query query, String collectionName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns and removes all documents matching the given query form the collection used to store the entityClass.
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param entityClass
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
<T> List<T> findAllAndRemove(Query query, Class<T> entityClass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns and removes all documents that match the provided query document criteria from the the collection used to
|
||||||
|
* store the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in
|
||||||
|
* the query.
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param entityClass
|
||||||
|
* @param collectionName
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
<T> List<T> findAllAndRemove(Query query, Class<T> entityClass, String collectionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying {@link MongoConverter}.
|
* Returns the underlying {@link MongoConverter}.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -15,129 +15,92 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import com.mongodb.MongoOptions;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import com.mongodb.MongoOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory bean for construction of a MongoOptions instance
|
* A factory bean for construction of a {@link MongoOptions} instance.
|
||||||
*
|
*
|
||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @Author Mark Pollack
|
* @author Mark Pollack
|
||||||
|
* @author Mike Saavedra
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, InitializingBean {
|
public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, InitializingBean {
|
||||||
|
|
||||||
private static final MongoOptions MONGO_OPTIONS = new MongoOptions();
|
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
|
||||||
/**
|
|
||||||
* number of connections allowed per host will block if run out
|
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.connectionsPerHost;
|
||||||
*/
|
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
|
||||||
private int connectionsPerHost = MONGO_OPTIONS.connectionsPerHost;
|
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.maxWaitTime;
|
||||||
|
private int connectTimeout = DEFAULT_MONGO_OPTIONS.connectTimeout;
|
||||||
|
private int socketTimeout = DEFAULT_MONGO_OPTIONS.socketTimeout;
|
||||||
|
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.socketKeepAlive;
|
||||||
|
private boolean autoConnectRetry = DEFAULT_MONGO_OPTIONS.autoConnectRetry;
|
||||||
|
private long maxAutoConnectRetryTime = DEFAULT_MONGO_OPTIONS.maxAutoConnectRetryTime;
|
||||||
|
private int writeNumber = DEFAULT_MONGO_OPTIONS.w;
|
||||||
|
private int writeTimeout = DEFAULT_MONGO_OPTIONS.wtimeout;
|
||||||
|
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.fsync;
|
||||||
|
private boolean slaveOk = DEFAULT_MONGO_OPTIONS.slaveOk;
|
||||||
|
private boolean ssl;
|
||||||
|
private SSLSocketFactory sslSocketFactory;
|
||||||
|
|
||||||
|
private MongoOptions options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* multiplier for connectionsPerHost for # of threads that can block if connectionsPerHost is 10, and
|
* Configures the maximum number of connections allowed per host until we will block.
|
||||||
* threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an exception will
|
|
||||||
* be throw
|
|
||||||
*/
|
|
||||||
private int threadsAllowedToBlockForConnectionMultiplier = MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* max wait time of a blocking thread for a connection
|
|
||||||
*/
|
|
||||||
private int maxWaitTime = MONGO_OPTIONS.maxWaitTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* connect timeout in milliseconds. 0 is default and infinite
|
|
||||||
*/
|
|
||||||
private int connectTimeout = MONGO_OPTIONS.connectTimeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* socket timeout. 0 is default and infinite
|
|
||||||
*/
|
|
||||||
private int socketTimeout = MONGO_OPTIONS.socketTimeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This controls whether or not to have socket keep alive turned on (SO_KEEPALIVE).
|
|
||||||
*
|
*
|
||||||
* defaults to false
|
* @param connectionsPerHost
|
||||||
*/
|
|
||||||
public boolean socketKeepAlive = MONGO_OPTIONS.socketKeepAlive;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this controls whether or not on a connect, the system retries automatically
|
|
||||||
*/
|
|
||||||
private boolean autoConnectRetry = MONGO_OPTIONS.autoConnectRetry;
|
|
||||||
|
|
||||||
private long maxAutoConnectRetryTime = MONGO_OPTIONS.maxAutoConnectRetryTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This specifies the number of servers to wait for on the write operation, and exception raising behavior.
|
|
||||||
*
|
|
||||||
* Defaults to 0.
|
|
||||||
*/
|
|
||||||
private int writeNumber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This controls timeout for write operations in milliseconds.
|
|
||||||
*
|
|
||||||
* Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
|
|
||||||
*/
|
|
||||||
private int writeTimeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This controls whether or not to fsync.
|
|
||||||
*
|
|
||||||
* Defaults to false.
|
|
||||||
*/
|
|
||||||
private boolean writeFsync;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies if the driver is allowed to read from secondaries or slaves.
|
|
||||||
*
|
|
||||||
* Defaults to false
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private boolean slaveOk = MONGO_OPTIONS.slaveOk;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* number of connections allowed per host will block if run out
|
|
||||||
*/
|
*/
|
||||||
public void setConnectionsPerHost(int connectionsPerHost) {
|
public void setConnectionsPerHost(int connectionsPerHost) {
|
||||||
this.connectionsPerHost = connectionsPerHost;
|
this.connectionsPerHost = connectionsPerHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* multiplier for connectionsPerHost for # of threads that can block if connectionsPerHost is 10, and
|
* A multiplier for connectionsPerHost for # of threads that can block a connection. If connectionsPerHost is 10, and
|
||||||
* threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an exception will
|
* threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block. If more threads try to block an
|
||||||
* be throw
|
* exception will be thrown.
|
||||||
|
*
|
||||||
|
* @param threadsAllowedToBlockForConnectionMultiplier
|
||||||
*/
|
*/
|
||||||
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
||||||
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* max wait time of a blocking thread for a connection
|
* Max wait time of a blocking thread for a connection.
|
||||||
|
*
|
||||||
|
* @param maxWaitTime
|
||||||
*/
|
*/
|
||||||
public void setMaxWaitTime(int maxWaitTime) {
|
public void setMaxWaitTime(int maxWaitTime) {
|
||||||
this.maxWaitTime = maxWaitTime;
|
this.maxWaitTime = maxWaitTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connect timeout in milliseconds. 0 is default and infinite
|
* Configures the connect timeout in milliseconds. Defaults to 0 (infinite time).
|
||||||
|
*
|
||||||
|
* @param connectTimeout
|
||||||
*/
|
*/
|
||||||
public void setConnectTimeout(int connectTimeout) {
|
public void setConnectTimeout(int connectTimeout) {
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* socket timeout. 0 is default and infinite
|
* Configures the socket timeout. Defaults to 0 (infinite time).
|
||||||
|
*
|
||||||
|
* @param socketTimeout
|
||||||
*/
|
*/
|
||||||
public void setSocketTimeout(int socketTimeout) {
|
public void setSocketTimeout(int socketTimeout) {
|
||||||
this.socketTimeout = socketTimeout;
|
this.socketTimeout = socketTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controls whether or not to have socket keep alive
|
* Configures whether or not to have socket keep alive turned on (SO_KEEPALIVE). Defaults to {@literal false}.
|
||||||
*
|
*
|
||||||
* @param socketKeepAlive
|
* @param socketKeepAlive
|
||||||
*/
|
*/
|
||||||
@@ -152,7 +115,7 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
* <li>-1 = don't even report network errors</li>
|
* <li>-1 = don't even report network errors</li>
|
||||||
* <li>0 = default, don't call getLastError by default</li>
|
* <li>0 = default, don't call getLastError by default</li>
|
||||||
* <li>1 = basic, call getLastError, but don't wait for slaves</li>
|
* <li>1 = basic, call getLastError, but don't wait for slaves</li>
|
||||||
* <li>2+= wait for slaves</li>
|
* <li>2 += wait for slaves</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
|
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
|
||||||
@@ -162,33 +125,33 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controls timeout for write operations in milliseconds. The 'wtimeout' option to the getlasterror command.
|
* Configures the timeout for write operations in milliseconds. This defaults to {@literal 0} (indefinite).
|
||||||
*
|
*
|
||||||
* @param writeTimeout Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
|
* @param writeTimeout
|
||||||
*/
|
*/
|
||||||
public void setWriteTimeout(int writeTimeout) {
|
public void setWriteTimeout(int writeTimeout) {
|
||||||
this.writeTimeout = writeTimeout;
|
this.writeTimeout = writeTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controls whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to false.
|
* Configures whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to {@literal false}.
|
||||||
*
|
*
|
||||||
* @param writeFsync to fsync on write (true), otherwise false.
|
* @param writeFsync to fsync on <code>write (true)<code>, otherwise {@literal false}.
|
||||||
*/
|
*/
|
||||||
public void setWriteFsync(boolean writeFsync) {
|
public void setWriteFsync(boolean writeFsync) {
|
||||||
this.writeFsync = writeFsync;
|
this.writeFsync = writeFsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this controls whether or not on a connect, the system retries automatically
|
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
|
||||||
*/
|
*/
|
||||||
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
||||||
this.autoConnectRetry = autoConnectRetry;
|
this.autoConnectRetry = autoConnectRetry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum amount of time in millisecons to spend retrying to open connection to the same server. Default is 0,
|
* Configures the maximum amount of time in millisecons to spend retrying to open connection to the same server. This
|
||||||
* which means to use the default 15s if 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
|
||||||
*/
|
*/
|
||||||
@@ -197,7 +160,7 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to 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.
|
||||||
*/
|
*/
|
||||||
@@ -205,32 +168,81 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
|||||||
this.slaveOk = slaveOk;
|
this.slaveOk = slaveOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
/**
|
||||||
|
* Specifies if the driver should use an SSL connection to Mongo. This defaults to {@literal false}. By default
|
||||||
|
* {@link SSLSocketFactory#getDefault()} will be used. See {@link #setSslSocketFactory(SSLSocketFactory)} if you want
|
||||||
|
* to configure a custom factory.
|
||||||
|
*
|
||||||
|
* @param ssl true if the driver should use an SSL connection.
|
||||||
|
* @see #setSslSocketFactory(SSLSocketFactory)
|
||||||
|
*/
|
||||||
|
public void setSsl(boolean ssl) {
|
||||||
|
this.ssl = ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the {@link SSLSocketFactory} to use for creating SSL connections to Mongo. Defaults to
|
||||||
|
* {@link SSLSocketFactory#getDefault()}. Implicitly activates {@link #setSsl(boolean)} if a non-{@literal null} value
|
||||||
|
* is given.
|
||||||
|
*
|
||||||
|
* @param sslSocketFactory the sslSocketFactory to use.
|
||||||
|
* @see #setSsl(boolean)
|
||||||
|
*/
|
||||||
|
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||||
|
|
||||||
|
setSsl(sslSocketFactory != null);
|
||||||
|
this.sslSocketFactory = sslSocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
|
*/
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
MONGO_OPTIONS.connectionsPerHost = connectionsPerHost;
|
|
||||||
MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
MongoOptions options = new MongoOptions();
|
||||||
MONGO_OPTIONS.maxWaitTime = maxWaitTime;
|
|
||||||
MONGO_OPTIONS.connectTimeout = connectTimeout;
|
options.connectionsPerHost = connectionsPerHost;
|
||||||
MONGO_OPTIONS.socketTimeout = socketTimeout;
|
options.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||||
MONGO_OPTIONS.socketKeepAlive = socketKeepAlive;
|
options.maxWaitTime = maxWaitTime;
|
||||||
MONGO_OPTIONS.autoConnectRetry = autoConnectRetry;
|
options.connectTimeout = connectTimeout;
|
||||||
MONGO_OPTIONS.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
options.socketTimeout = socketTimeout;
|
||||||
MONGO_OPTIONS.slaveOk = slaveOk;
|
options.socketKeepAlive = socketKeepAlive;
|
||||||
MONGO_OPTIONS.w = writeNumber;
|
options.autoConnectRetry = autoConnectRetry;
|
||||||
MONGO_OPTIONS.wtimeout = writeTimeout;
|
options.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
||||||
MONGO_OPTIONS.fsync = writeFsync;
|
options.slaveOk = slaveOk;
|
||||||
|
options.w = writeNumber;
|
||||||
|
options.wtimeout = writeTimeout;
|
||||||
|
options.fsync = writeFsync;
|
||||||
|
|
||||||
|
if (ssl) {
|
||||||
|
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||||
|
*/
|
||||||
public MongoOptions getObject() {
|
public MongoOptions getObject() {
|
||||||
return MONGO_OPTIONS;
|
return this.options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||||
|
*/
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return MongoOptions.class;
|
return MongoOptions.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||||
|
*/
|
||||||
public boolean isSingleton() {
|
public boolean isSingleton() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-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;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import org.springframework.transaction.support.ResourceHolder;
|
import org.springframework.transaction.support.ResourceHolder;
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
class MongoSynchronization extends ResourceHolderSynchronization<ResourceHolder, Object> {
|
class MongoSynchronization extends ResourceHolderSynchronization<ResourceHolder, Object> {
|
||||||
|
|
||||||
public MongoSynchronization(ResourceHolder resourceHolder, Object resourceKey) {
|
public MongoSynchronization(ResourceHolder resourceHolder, Object resourceKey) {
|
||||||
|
|||||||
@@ -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 java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -46,9 +47,13 @@ import org.springframework.core.io.ResourceLoader;
|
|||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.dao.OptimisticLockingFailureException;
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.authentication.UserCredentials;
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
import org.springframework.data.convert.EntityReader;
|
import org.springframework.data.convert.EntityReader;
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.geo.Distance;
|
||||||
|
import org.springframework.data.geo.GeoResult;
|
||||||
|
import org.springframework.data.geo.Metric;
|
||||||
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.BeanWrapper;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
@@ -59,15 +64,14 @@ import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
|||||||
import org.springframework.data.mongodb.core.aggregation.Fields;
|
import org.springframework.data.mongodb.core.aggregation.Fields;
|
||||||
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
|
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
|
||||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
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.Distance;
|
|
||||||
import org.springframework.data.mongodb.core.geo.GeoResult;
|
|
||||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
import org.springframework.data.mongodb.core.geo.GeoResults;
|
||||||
import org.springframework.data.mongodb.core.geo.Metric;
|
|
||||||
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;
|
||||||
@@ -92,6 +96,7 @@ 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.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.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -110,7 +115,6 @@ 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}.
|
||||||
*
|
*
|
||||||
@@ -123,7 +127,10 @@ import com.mongodb.util.JSONParseException;
|
|||||||
* @author Tobias Trelle
|
* @author Tobias Trelle
|
||||||
* @author Sebastian Herold
|
* @author Sebastian Herold
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Chuong Ngo
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class);
|
||||||
@@ -144,7 +151,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
private final MongoConverter mongoConverter;
|
private final MongoConverter mongoConverter;
|
||||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
private final MongoDbFactory mongoDbFactory;
|
private final MongoDbFactory mongoDbFactory;
|
||||||
private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
|
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||||
private final QueryMapper queryMapper;
|
private final QueryMapper queryMapper;
|
||||||
private final UpdateMapper updateMapper;
|
private final UpdateMapper updateMapper;
|
||||||
|
|
||||||
@@ -198,6 +205,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
Assert.notNull(mongoDbFactory);
|
Assert.notNull(mongoDbFactory);
|
||||||
|
|
||||||
this.mongoDbFactory = mongoDbFactory;
|
this.mongoDbFactory = mongoDbFactory;
|
||||||
|
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||||
this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
|
this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
|
||||||
this.queryMapper = new QueryMapper(this.mongoConverter);
|
this.queryMapper = new QueryMapper(this.mongoConverter);
|
||||||
this.updateMapper = new UpdateMapper(this.mongoConverter);
|
this.updateMapper = new UpdateMapper(this.mongoConverter);
|
||||||
@@ -364,12 +372,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
Assert.notNull(query);
|
Assert.notNull(query);
|
||||||
|
|
||||||
DBObject queryObject = query.getQueryObject();
|
DBObject queryObject = queryMapper.getMappedObject(query.getQueryObject(), null);
|
||||||
DBObject sortObject = query.getSortObject();
|
DBObject sortObject = query.getSortObject();
|
||||||
DBObject fieldsObject = query.getFieldsObject();
|
DBObject fieldsObject = query.getFieldsObject();
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: $s",
|
LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: %s",
|
||||||
serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
|
serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,8 +573,26 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
mongoConverter, entityClass), near.getMetric());
|
mongoConverter, entityClass), near.getMetric());
|
||||||
List<GeoResult<T>> result = new ArrayList<GeoResult<T>>(results.size());
|
List<GeoResult<T>> result = new ArrayList<GeoResult<T>>(results.size());
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
int elementsToSkip = near.getSkip() != null ? near.getSkip() : 0;
|
||||||
|
|
||||||
for (Object element : results) {
|
for (Object element : results) {
|
||||||
result.add(callback.doWith((DBObject) element));
|
|
||||||
|
/*
|
||||||
|
* As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries
|
||||||
|
* we skip the elements ourselves to avoid at least the document 2 object mapping overhead.
|
||||||
|
*
|
||||||
|
* @see https://jira.mongodb.org/browse/SERVER-3925
|
||||||
|
*/
|
||||||
|
if (index >= elementsToSkip) {
|
||||||
|
result.add(callback.doWith((DBObject) element));
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementsToSkip > 0) {
|
||||||
|
// as we skipped some elements we have to calculate the averageDistance ourselves:
|
||||||
|
return new GeoResults<T>(result, near.getMetric());
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject stats = (DBObject) commandResult.get("stats");
|
DBObject stats = (DBObject) commandResult.get("stats");
|
||||||
@@ -681,10 +707,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
initializeVersionProperty(objectToSave);
|
initializeVersionProperty(objectToSave);
|
||||||
|
|
||||||
BasicDBObject dbDoc = new BasicDBObject();
|
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
|
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
|
||||||
writer.write(objectToSave, dbDoc);
|
|
||||||
|
DBObject dbDoc = toDbObject(objectToSave, writer);
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
|
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
|
||||||
Object id = insertDBObject(collectionName, dbDoc, objectToSave.getClass());
|
Object id = insertDBObject(collectionName, dbDoc, objectToSave.getClass());
|
||||||
@@ -693,13 +718,32 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc));
|
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param objectToSave
|
||||||
|
* @param writer
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private <T> DBObject toDbObject(T objectToSave, MongoWriter<T> writer) {
|
||||||
|
|
||||||
|
if (!(objectToSave instanceof String)) {
|
||||||
|
DBObject dbDoc = new BasicDBObject();
|
||||||
|
writer.write(objectToSave, dbDoc);
|
||||||
|
return dbDoc;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return (DBObject) JSON.parse((String) objectToSave);
|
||||||
|
} catch (JSONParseException e) {
|
||||||
|
throw new MappingException("Could not parse given String to save into a JSON document!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeVersionProperty(Object entity) {
|
private void initializeVersionProperty(Object entity) {
|
||||||
|
|
||||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
||||||
|
|
||||||
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
||||||
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity,
|
BeanWrapper<Object> wrapper = BeanWrapper.create(entity, this.mongoConverter.getConversionService());
|
||||||
this.mongoConverter.getConversionService());
|
|
||||||
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -793,12 +837,11 @@ 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<PersistentEntity<T, ?>, T> beanWrapper = BeanWrapper.create(objectToSave,
|
BeanWrapper<T> beanWrapper = BeanWrapper.create(objectToSave, this.mongoConverter.getConversionService());
|
||||||
this.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, !versionProperty.usePropertyAccess());
|
Number version = beanWrapper.getProperty(versionProperty, Number.class);
|
||||||
|
|
||||||
// Fresh instance -> initialize version property
|
// Fresh instance -> initialize version property
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
@@ -812,7 +855,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
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, false);
|
Number number = beanWrapper.getProperty(versionProperty, Number.class);
|
||||||
beanWrapper.setProperty(versionProperty, number.longValue() + 1);
|
beanWrapper.setProperty(versionProperty, number.longValue() + 1);
|
||||||
|
|
||||||
BasicDBObject dbObject = new BasicDBObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
@@ -832,19 +875,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
assertUpdateableIdIfNotSet(objectToSave);
|
assertUpdateableIdIfNotSet(objectToSave);
|
||||||
|
|
||||||
DBObject dbDoc = new BasicDBObject();
|
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
|
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
|
||||||
|
|
||||||
if (!(objectToSave instanceof String)) {
|
DBObject dbDoc = toDbObject(objectToSave, writer);
|
||||||
writer.write(objectToSave, dbDoc);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
dbDoc = (DBObject) JSON.parse((String) objectToSave);
|
|
||||||
} catch (JSONParseException e) {
|
|
||||||
throw new MappingException("Could not parse given String to save into a JSON document!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
|
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
|
||||||
Object id = saveDBObject(collectionName, dbDoc, objectToSave.getClass());
|
Object id = saveDBObject(collectionName, dbDoc, objectToSave.getClass());
|
||||||
@@ -928,6 +961,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return doUpdate(collectionName, query, update, null, true, false);
|
return doUpdate(collectionName, query, update, null, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WriteResult upsert(Query query, Update update, Class<?> entityClass, String collectionName) {
|
||||||
|
return doUpdate(collectionName, query, update, entityClass, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
public WriteResult updateFirst(Query query, Update update, Class<?> entityClass) {
|
public WriteResult updateFirst(Query query, Update update, Class<?> entityClass) {
|
||||||
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, false);
|
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, false);
|
||||||
}
|
}
|
||||||
@@ -936,6 +973,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return doUpdate(collectionName, query, update, null, false, false);
|
return doUpdate(collectionName, query, update, null, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WriteResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName) {
|
||||||
|
return doUpdate(collectionName, query, update, entityClass, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
public WriteResult updateMulti(Query query, Update update, Class<?> entityClass) {
|
public WriteResult updateMulti(Query query, Update update, Class<?> entityClass) {
|
||||||
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, true);
|
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, true);
|
||||||
}
|
}
|
||||||
@@ -944,6 +985,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return doUpdate(collectionName, query, update, null, false, true);
|
return doUpdate(collectionName, query, update, null, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WriteResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName) {
|
||||||
|
return doUpdate(collectionName, query, update, entityClass, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected WriteResult doUpdate(final String collectionName, final Query query, final Update update,
|
protected WriteResult doUpdate(final String collectionName, final Query query, final Update update,
|
||||||
final Class<?> entityClass, final boolean upsert, final boolean multi) {
|
final Class<?> entityClass, final boolean upsert, final boolean multi) {
|
||||||
|
|
||||||
@@ -952,6 +997,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
MongoPersistentEntity<?> entity = entityClass == null ? null : getPersistentEntity(entityClass);
|
MongoPersistentEntity<?> entity = entityClass == null ? null : getPersistentEntity(entityClass);
|
||||||
|
|
||||||
|
increaseVersionForUpdateIfNecessary(entity, update);
|
||||||
|
|
||||||
DBObject queryObj = query == null ? new BasicDBObject() : queryMapper.getMappedObject(query.getQueryObject(),
|
DBObject queryObj = query == null ? new BasicDBObject() : queryMapper.getMappedObject(query.getQueryObject(),
|
||||||
entity);
|
entity);
|
||||||
DBObject updateObj = update == null ? new BasicDBObject() : updateMapper.getMappedObject(
|
DBObject updateObj = update == null ? new BasicDBObject() : updateMapper.getMappedObject(
|
||||||
@@ -969,7 +1016,7 @@ 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) {
|
if (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);
|
||||||
}
|
}
|
||||||
@@ -981,24 +1028,67 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Object object) {
|
private void increaseVersionForUpdateIfNecessary(MongoPersistentEntity<?> persistentEntity, Update update) {
|
||||||
|
|
||||||
if (object == null) {
|
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
|
||||||
return;
|
String versionFieldName = persistentEntity.getVersionProperty().getFieldName();
|
||||||
|
if (!update.modifies(versionFieldName)) {
|
||||||
|
update.inc(versionFieldName, 1L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(getIdQueryFor(object), object.getClass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Object object, String collection) {
|
private boolean dbObjectContainsVersionProperty(DBObject dbObject, MongoPersistentEntity<?> persistentEntity) {
|
||||||
|
|
||||||
|
if (persistentEntity == null || !persistentEntity.hasVersionProperty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbObject.containsField(persistentEntity.getVersionProperty().getFieldName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriteResult remove(Object object) {
|
||||||
|
|
||||||
|
if (object == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return remove(getIdQueryFor(object), object.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriteResult remove(Object object, String collection) {
|
||||||
|
|
||||||
Assert.hasText(collection);
|
Assert.hasText(collection);
|
||||||
|
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
doRemove(collection, getIdQueryFor(object), object.getClass());
|
return doRemove(collection, getIdQueryFor(object), object.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link Entry} containing the {@link MongoPersistentProperty} defining the {@literal id} as
|
||||||
|
* {@link Entry#getKey()} and the {@link Id}s property value as its {@link Entry#getValue()}.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Map.Entry<MongoPersistentProperty, Object> extractIdPropertyAndValue(Object object) {
|
||||||
|
|
||||||
|
Assert.notNull(object, "Id cannot be extracted from 'null'.");
|
||||||
|
|
||||||
|
Class<?> objectType = object.getClass();
|
||||||
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
||||||
|
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
||||||
|
|
||||||
|
if (idProp == null) {
|
||||||
|
throw new MappingException("No id property found for object of type " + objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object idValue = BeanWrapper.create(object, mongoConverter.getConversionService())
|
||||||
|
.getProperty(idProp, Object.class);
|
||||||
|
return Collections.singletonMap(idProp, idValue).entrySet().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1009,21 +1099,31 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
*/
|
*/
|
||||||
private Query getIdQueryFor(Object object) {
|
private Query getIdQueryFor(Object object) {
|
||||||
|
|
||||||
Assert.notNull(object);
|
Map.Entry<MongoPersistentProperty, Object> id = extractIdPropertyAndValue(object);
|
||||||
|
return new Query(where(id.getKey().getFieldName()).is(id.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
Class<?> objectType = object.getClass();
|
/**
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
* Returns a {@link Query} for the given entities by their ids.
|
||||||
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
*
|
||||||
|
* @param objects must not be {@literal null} or {@literal empty}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Query getIdInQueryFor(Collection<?> objects) {
|
||||||
|
|
||||||
if (idProp == null) {
|
Assert.notEmpty(objects, "Cannot create Query for empty collection.");
|
||||||
throw new MappingException("No id property found for object of type " + objectType);
|
|
||||||
|
Iterator<?> it = objects.iterator();
|
||||||
|
Map.Entry<MongoPersistentProperty, Object> firstEntry = extractIdPropertyAndValue(it.next());
|
||||||
|
|
||||||
|
ArrayList<Object> ids = new ArrayList<Object>(objects.size());
|
||||||
|
ids.add(firstEntry.getValue());
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
ids.add(extractIdPropertyAndValue(it.next()).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionService service = mongoConverter.getConversionService();
|
return new Query(where(firstEntry.getKey().getFieldName()).in(ids));
|
||||||
Object idProperty = null;
|
|
||||||
|
|
||||||
idProperty = BeanWrapper.create(object, service).getProperty(idProp, Object.class, true);
|
|
||||||
return new Query(where(idProp.getFieldName()).is(idProperty));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertUpdateableIdIfNotSet(Object entity) {
|
private void assertUpdateableIdIfNotSet(Object entity) {
|
||||||
@@ -1036,7 +1136,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConversionService service = mongoConverter.getConversionService();
|
ConversionService service = mongoConverter.getConversionService();
|
||||||
Object idValue = BeanWrapper.create(entity, service).getProperty(idProperty, Object.class, true);
|
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(
|
||||||
@@ -1045,19 +1145,19 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Query query, String collectionName) {
|
public WriteResult remove(Query query, String collectionName) {
|
||||||
remove(query, null, collectionName);
|
return remove(query, null, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Query query, Class<?> entityClass) {
|
public WriteResult remove(Query query, Class<?> entityClass) {
|
||||||
remove(query, entityClass, determineCollectionName(entityClass));
|
return remove(query, entityClass, determineCollectionName(entityClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Query query, Class<?> entityClass, String collectionName) {
|
public WriteResult remove(Query query, Class<?> entityClass, String collectionName) {
|
||||||
doRemove(collectionName, query, entityClass);
|
return doRemove(collectionName, query, entityClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> void doRemove(final String collectionName, final Query query, final Class<T> entityClass) {
|
protected <T> WriteResult doRemove(final String collectionName, final Query query, final Class<T> entityClass) {
|
||||||
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null!");
|
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null!");
|
||||||
@@ -1068,8 +1168,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
final DBObject queryObject = query.getQueryObject();
|
final DBObject queryObject = query.getQueryObject();
|
||||||
final MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
|
final MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
|
||||||
|
|
||||||
execute(collectionName, new CollectionCallback<Void>() {
|
return execute(collectionName, new CollectionCallback<WriteResult>() {
|
||||||
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public WriteResult doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeDeleteEvent<T>(queryObject, entityClass));
|
maybeEmitEvent(new BeforeDeleteEvent<T>(queryObject, entityClass));
|
||||||
|
|
||||||
@@ -1085,11 +1185,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
|
WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
|
||||||
writeConcernToUse);
|
writeConcernToUse);
|
||||||
|
|
||||||
handleAnyWriteResultErrors(wr, dboq, MongoActionOperation.REMOVE);
|
handleAnyWriteResultErrors(wr, dboq, MongoActionOperation.REMOVE);
|
||||||
|
|
||||||
maybeEmitEvent(new AfterDeleteEvent<T>(queryObject, entityClass));
|
maybeEmitEvent(new AfterDeleteEvent<T>(queryObject, entityClass));
|
||||||
|
|
||||||
return null;
|
return wr;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1123,6 +1224,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
public <T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction,
|
public <T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction,
|
||||||
String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass) {
|
String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass) {
|
||||||
|
|
||||||
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
|
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
|
||||||
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
|
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
|
||||||
DBCollection inputCollection = getCollection(inputCollectionName);
|
DBCollection inputCollection = getCollection(inputCollectionName);
|
||||||
@@ -1147,12 +1249,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
|
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);
|
||||||
|
|
||||||
for (DBObject dbObject : mapReduceOutput.results()) {
|
for (DBObject dbObject : mapReduceOutput.results()) {
|
||||||
mappedResults.add(callback.doWith(dbObject));
|
mappedResults.add(callback.doWith(dbObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
MapReduceResults<T> mapReduceResult = new MapReduceResults<T>(mappedResults, commandResult);
|
return new MapReduceResults<T>(mappedResults, commandResult);
|
||||||
return mapReduceResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> GroupByResults<T> group(String inputCollectionName, GroupBy groupBy, Class<T> entityClass) {
|
public <T> GroupByResults<T> group(String inputCollectionName, GroupBy groupBy, Class<T> entityClass) {
|
||||||
@@ -1206,15 +1308,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Iterable<DBObject> resultSet = (Iterable<DBObject>) commandResult.get("retval");
|
Iterable<DBObject> resultSet = (Iterable<DBObject>) commandResult.get("retval");
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
for (DBObject dbObject : resultSet) {
|
for (DBObject dbObject : resultSet) {
|
||||||
mappedResults.add(callback.doWith(dbObject));
|
mappedResults.add(callback.doWith(dbObject));
|
||||||
}
|
}
|
||||||
GroupByResults<T> groupByResult = new GroupByResults<T>(mappedResults, commandResult);
|
|
||||||
return groupByResult;
|
|
||||||
|
|
||||||
|
return new GroupByResults<T>(mappedResults, commandResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1245,6 +1346,54 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
return aggregate(aggregation, collectionName, outputType, null);
|
return aggregate(aggregation, collectionName, outputType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#findAllAndRemove(org.springframework.data.mongodb.core.query.Query, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<T> findAllAndRemove(Query query, String collectionName) {
|
||||||
|
return findAndRemove(query, null, collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#findAllAndRemove(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<T> findAllAndRemove(Query query, Class<T> entityClass) {
|
||||||
|
return findAllAndRemove(query, entityClass, determineCollectionName(entityClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.MongoOperations#findAllAndRemove(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<T> findAllAndRemove(Query query, Class<T> entityClass, String collectionName) {
|
||||||
|
return doFindAndDelete(collectionName, query, entityClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve and remove all documents matching the given {@code query} by calling {@link #find(Query, Class, String)}
|
||||||
|
* and {@link #remove(Query, Class, String)}, whereas the {@link Query} for {@link #remove(Query, Class, String)} is
|
||||||
|
* constructed out of the find result.
|
||||||
|
*
|
||||||
|
* @param collectionName
|
||||||
|
* @param query
|
||||||
|
* @param entityClass
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected <T> List<T> doFindAndDelete(String collectionName, Query query, Class<T> entityClass) {
|
||||||
|
|
||||||
|
List<T> result = find(query, entityClass, collectionName);
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(result)) {
|
||||||
|
remove(getIdInQueryFor(result), entityClass, collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType,
|
protected <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType,
|
||||||
AggregationOperationContext context) {
|
AggregationOperationContext context) {
|
||||||
|
|
||||||
@@ -1507,8 +1656,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||||
|
|
||||||
DBObject mappedUpdate = queryMapper.getMappedObject(update.getUpdateObject(), entity);
|
increaseVersionForUpdateIfNecessary(entity, update);
|
||||||
|
|
||||||
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
|
DBObject mappedQuery = queryMapper.getMappedObject(query, 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("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort
|
||||||
@@ -1544,9 +1695,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConversionService conversionService = mongoConverter.getConversionService();
|
ConversionService conversionService = mongoConverter.getConversionService();
|
||||||
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(savedObject, conversionService);
|
BeanWrapper<Object> wrapper = BeanWrapper.create(savedObject, conversionService);
|
||||||
|
|
||||||
Object idValue = wrapper.getProperty(idProp, idProp.getType(), true);
|
Object idValue = wrapper.getProperty(idProp, idProp.getType());
|
||||||
|
|
||||||
if (idValue != null) {
|
if (idValue != null) {
|
||||||
return;
|
return;
|
||||||
@@ -1783,7 +1934,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final MongoConverter getDefaultMongoConverter(MongoDbFactory factory) {
|
private static final MongoConverter getDefaultMongoConverter(MongoDbFactory factory) {
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
|
|
||||||
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
|
||||||
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
|
||||||
converter.afterPropertiesSet();
|
converter.afterPropertiesSet();
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,9 +19,11 @@ import java.net.UnknownHostException;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.authentication.UserCredentials;
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
@@ -34,6 +36,7 @@ import com.mongodb.WriteConcern;
|
|||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||||
|
|
||||||
@@ -41,6 +44,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
private final String databaseName;
|
private final String databaseName;
|
||||||
private final boolean mongoInstanceCreated;
|
private final boolean mongoInstanceCreated;
|
||||||
private final UserCredentials credentials;
|
private final UserCredentials credentials;
|
||||||
|
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||||
|
private final String authenticationDatabaseName;
|
||||||
|
|
||||||
private WriteConcern writeConcern;
|
private WriteConcern writeConcern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +56,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @param databaseName database name, not be {@literal null} or empty.
|
* @param databaseName database name, not be {@literal null} or empty.
|
||||||
*/
|
*/
|
||||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
||||||
this(mongo, databaseName, UserCredentials.NO_CREDENTIALS, false);
|
this(mongo, databaseName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,7 +67,20 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @param credentials username and password.
|
* @param credentials username and password.
|
||||||
*/
|
*/
|
||||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||||
this(mongo, databaseName, credentials, false);
|
this(mongo, databaseName, credentials, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
|
||||||
|
*
|
||||||
|
* @param mongo Mongo instance, must not be {@literal null}.
|
||||||
|
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||||
|
* @param credentials username and password.
|
||||||
|
* @param authenticationDatabaseName the database name to use for authentication
|
||||||
|
*/
|
||||||
|
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
|
String authenticationDatabaseName) {
|
||||||
|
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,12 +91,14 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
* @throws UnknownHostException
|
* @throws UnknownHostException
|
||||||
* @see MongoURI
|
* @see MongoURI
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
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())), true);
|
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
|
||||||
|
true, uri.getDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||||
boolean mongoInstanceCreated) {
|
boolean mongoInstanceCreated, String authenticationDatabaseName) {
|
||||||
|
|
||||||
Assert.notNull(mongo, "Mongo must not be null");
|
Assert.notNull(mongo, "Mongo must not be null");
|
||||||
Assert.hasText(databaseName, "Database name must not be empty");
|
Assert.hasText(databaseName, "Database name must not be empty");
|
||||||
@@ -88,6 +109,12 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
this.databaseName = databaseName;
|
this.databaseName = databaseName;
|
||||||
this.mongoInstanceCreated = mongoInstanceCreated;
|
this.mongoInstanceCreated = mongoInstanceCreated;
|
||||||
this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
|
this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
|
||||||
|
this.exceptionTranslator = new MongoExceptionTranslator();
|
||||||
|
this.authenticationDatabaseName = StringUtils.hasText(authenticationDatabaseName) ? authenticationDatabaseName
|
||||||
|
: databaseName;
|
||||||
|
|
||||||
|
Assert.isTrue(this.authenticationDatabaseName.matches("[\\w-]+"),
|
||||||
|
"Authentication database name must only contain letters, numbers, underscores and dashes!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,7 +142,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
|
|
||||||
Assert.hasText(dbName, "Database name must not be empty.");
|
Assert.hasText(dbName, "Database name must not be empty.");
|
||||||
|
|
||||||
DB db = MongoDbUtils.getDB(mongo, dbName, credentials);
|
DB db = MongoDbUtils.getDB(mongo, dbName, credentials, authenticationDatabaseName);
|
||||||
|
|
||||||
if (writeConcern != null) {
|
if (writeConcern != null) {
|
||||||
db.setWriteConcern(writeConcern);
|
db.setWriteConcern(writeConcern);
|
||||||
@@ -138,4 +165,13 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
|||||||
private static String parseChars(char[] chars) {
|
private static String parseChars(char[] chars) {
|
||||||
return chars == null ? null : String.valueOf(chars);
|
return chars == null ? null : String.valueOf(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.MongoDbFactory#getExceptionTranslator()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PersistenceExceptionTranslator getExceptionTranslator() {
|
||||||
|
return this.exceptionTranslator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,15 @@ public class Aggregation {
|
|||||||
|
|
||||||
private final List<AggregationOperation> operations;
|
private final List<AggregationOperation> operations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @param operations must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
public static Aggregation newAggregation(List<? extends AggregationOperation> operations) {
|
||||||
|
return newAggregation(operations.toArray(new AggregationOperation[operations.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||||
*
|
*
|
||||||
@@ -57,6 +66,16 @@ public class Aggregation {
|
|||||||
return new Aggregation(operations);
|
return new Aggregation(operations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @param type must not be {@literal null}.
|
||||||
|
* @param operations must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
public static <T> TypedAggregation<T> newAggregation(Class<T> type, List<? extends AggregationOperation> operations) {
|
||||||
|
return newAggregation(type, operations.toArray(new AggregationOperation[operations.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
@@ -227,8 +246,9 @@ public class Aggregation {
|
|||||||
|
|
||||||
operationDocuments.add(operation.toDBObject(context));
|
operationDocuments.add(operation.toDBObject(context));
|
||||||
|
|
||||||
if (operation instanceof AggregationOperationContext) {
|
if (operation instanceof FieldsExposingAggregationOperation) {
|
||||||
context = (AggregationOperationContext) operation;
|
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
|
||||||
|
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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 org.springframework.data.mongodb.core.aggregation.AggregationExpressionTransformer.AggregationExpressionTransformationContext;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||||
|
import org.springframework.data.mongodb.core.spel.ExpressionNode;
|
||||||
|
import org.springframework.data.mongodb.core.spel.ExpressionTransformationContextSupport;
|
||||||
|
import org.springframework.data.mongodb.core.spel.ExpressionTransformer;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to type an {@link ExpressionTransformer} to the contained
|
||||||
|
* {@link AggregationExpressionTransformationContext}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
interface AggregationExpressionTransformer extends
|
||||||
|
ExpressionTransformer<AggregationExpressionTransformationContext<ExpressionNode>> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special {@link ExpressionTransformationContextSupport} to be aware of the {@link AggregationOperationContext}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public static class AggregationExpressionTransformationContext<T extends ExpressionNode> extends
|
||||||
|
ExpressionTransformationContextSupport<T> {
|
||||||
|
|
||||||
|
private final AggregationOperationContext aggregationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@link AggregationExpressionTransformationContext}.
|
||||||
|
*
|
||||||
|
* @param currentNode must not be {@literal null}.
|
||||||
|
* @param parentNode
|
||||||
|
* @param previousOperationObject
|
||||||
|
* @param aggregationContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public AggregationExpressionTransformationContext(T currentNode, ExpressionNode parentNode,
|
||||||
|
DBObject previousOperationObject, AggregationOperationContext context) {
|
||||||
|
|
||||||
|
super(currentNode, parentNode, previousOperationObject);
|
||||||
|
|
||||||
|
Assert.notNull(context, "AggregationOperationContext must not be null!");
|
||||||
|
this.aggregationContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the underlying {@link AggregationOperationContext}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AggregationOperationContext getAggregationContext() {
|
||||||
|
return aggregationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link FieldReference} for the current {@link ExpressionNode}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public FieldReference getFieldReference() {
|
||||||
|
return aggregationContext.getReference(getCurrentNode().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
@@ -29,9 +29,10 @@ import org.springframework.util.CompositeIterator;
|
|||||||
* Value object to capture the fields exposed by an {@link AggregationOperation}.
|
* Value object to capture the fields exposed by an {@link AggregationOperation}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class ExposedFields implements Iterable<ExposedField> {
|
public final class ExposedFields implements Iterable<ExposedField> {
|
||||||
|
|
||||||
private static final List<ExposedField> NO_FIELDS = Collections.emptyList();
|
private static final List<ExposedField> NO_FIELDS = Collections.emptyList();
|
||||||
private static final ExposedFields EMPTY = new ExposedFields(NO_FIELDS, NO_FIELDS);
|
private static final ExposedFields EMPTY = new ExposedFields(NO_FIELDS, NO_FIELDS);
|
||||||
@@ -151,13 +152,47 @@ public class ExposedFields implements Iterable<ExposedField> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExposedFields} exposes no non-synthetic fields at all.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean exposesNoNonSyntheticFields() {
|
||||||
|
return originalFields.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExposedFields} exposes a single non-synthetic field only.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean exposesSingleNonSyntheticFieldOnly() {
|
||||||
|
return originalFields.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExposedFields} exposes no fields at all.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean exposesNoFields() {
|
||||||
|
return exposedFieldsCount() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the {@link ExposedFields} exposes a single field only.
|
* Returns whether the {@link ExposedFields} exposes a single field only.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean exposesSingleFieldOnly() {
|
boolean exposesSingleFieldOnly() {
|
||||||
return originalFields.size() + syntheticFields.size() == 1;
|
return exposedFieldsCount() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int exposedFieldsCount() {
|
||||||
|
return originalFields.size() + syntheticFields.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -224,6 +259,15 @@ public class ExposedFields implements Iterable<ExposedField> {
|
|||||||
return field.getTarget();
|
return field.getTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.Field#isAliased()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isAliased() {
|
||||||
|
return field.isAliased();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the field can be referred to using the given name.
|
* Returns whether the field can be referred to using the given name.
|
||||||
*
|
*
|
||||||
@@ -242,6 +286,41 @@ public class ExposedFields implements Iterable<ExposedField> {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("AggregationField: %s, synthetic: %s", field, synthetic);
|
return String.format("AggregationField: %s, synthetic: %s", field, synthetic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof ExposedField)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedField that = (ExposedField) obj;
|
||||||
|
|
||||||
|
return this.field.equals(that.field) && this.synthetic == that.synthetic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
|
||||||
|
int result = 17;
|
||||||
|
|
||||||
|
result += 31 * field.hashCode();
|
||||||
|
result += 31 * (synthetic ? 0 : 1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -270,10 +349,21 @@ public class ExposedFields implements Iterable<ExposedField> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String getRaw() {
|
public String getRaw() {
|
||||||
|
|
||||||
String target = field.getTarget();
|
String target = field.getTarget();
|
||||||
return field.synthetic ? target : String.format("%s.%s", Fields.UNDERSCORE_ID, target);
|
return field.synthetic ? target : String.format("%s.%s", Fields.UNDERSCORE_ID, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the referenve value for the given field reference. Will return 1 for a synthetic, unaliased field or the
|
||||||
|
* raw rendering of the reference otherwise.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getReferenceValue() {
|
||||||
|
return field.synthetic && !field.isAliased() ? 1 : toString();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
@@ -282,5 +372,34 @@ public class ExposedFields implements Iterable<ExposedField> {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("$%s", getRaw());
|
return String.format("$%s", getRaw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof FieldReference)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldReference that = (FieldReference) obj;
|
||||||
|
|
||||||
|
return this.field.equals(that.field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return field.hashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,17 +17,32 @@ package org.springframework.data.mongodb.core.aggregation;
|
|||||||
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support class to implement {@link AggregationOperation}s that will become an {@link AggregationOperationContext} as
|
* {@link AggregationOperationContext} that combines the available field references from a given
|
||||||
* well defining {@link ExposedFields}.
|
* {@code AggregationOperationContext} and an {@link FieldsExposingAggregationOperation}.
|
||||||
*
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
public abstract class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
|
class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
|
||||||
|
|
||||||
|
private final ExposedFields exposedFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}.
|
||||||
|
*
|
||||||
|
* @param exposedFields must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields) {
|
||||||
|
|
||||||
|
Assert.notNull(exposedFields, "ExposedFields must not be null!");
|
||||||
|
this.exposedFields = exposedFields;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
@@ -44,7 +59,7 @@ public abstract class ExposedFieldsAggregationOperationContext implements Aggreg
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(Field field) {
|
public FieldReference getReference(Field field) {
|
||||||
return getReference(field.getName());
|
return getReference(field.getTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -54,7 +69,7 @@ public abstract class ExposedFieldsAggregationOperationContext implements Aggreg
|
|||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(String name) {
|
public FieldReference getReference(String name) {
|
||||||
|
|
||||||
ExposedField field = getFields().getField(name);
|
ExposedField field = exposedFields.getField(name);
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
return new FieldReference(field);
|
return new FieldReference(field);
|
||||||
@@ -62,6 +77,4 @@ public abstract class ExposedFieldsAggregationOperationContext implements Aggreg
|
|||||||
|
|
||||||
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
|
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ExposedFields getFields();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,4 +36,11 @@ public interface Field {
|
|||||||
* @return must not be {@literal null}.
|
* @return must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
String getTarget();
|
String getTarget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the Field is aliased, which means it has a name set different from the target.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean isAliased();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -23,6 +23,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,13 +32,13 @@ import org.springframework.util.StringUtils;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class Fields implements Iterable<Field> {
|
public final class Fields implements Iterable<Field> {
|
||||||
|
|
||||||
private static final String AMBIGUOUS_EXCEPTION = "Found two fields both using '%s' as name: %s and %s! Please "
|
private static final String AMBIGUOUS_EXCEPTION = "Found two fields both using '%s' as name: %s and %s! Please "
|
||||||
+ "customize your field definitions to get to unique field names!";
|
+ "customize your field definitions to get to unique field names!";
|
||||||
|
|
||||||
public static String UNDERSCORE_ID = "_id";
|
public static final String UNDERSCORE_ID = "_id";
|
||||||
public static String UNDERSCORE_ID_REF = "$_id";
|
public static final String UNDERSCORE_ID_REF = "$_id";
|
||||||
|
|
||||||
private final List<Field> fields;
|
private final List<Field> fields;
|
||||||
|
|
||||||
@@ -196,17 +197,30 @@ public class Fields implements Iterable<Field> {
|
|||||||
|
|
||||||
public AggregationField(String name, String target) {
|
public AggregationField(String name, String target) {
|
||||||
|
|
||||||
Assert.hasText(name, "AggregationField name must not be null or empty!");
|
String nameToSet = cleanUp(name);
|
||||||
|
String targetToSet = cleanUp(target);
|
||||||
|
|
||||||
|
Assert.hasText(nameToSet, "AggregationField name must not be null or empty!");
|
||||||
|
|
||||||
if (target == null && name.contains(".")) {
|
if (target == null && name.contains(".")) {
|
||||||
this.name = name.substring(name.indexOf(".") + 1);
|
this.name = nameToSet.substring(nameToSet.indexOf('.') + 1);
|
||||||
this.target = name;
|
this.target = nameToSet;
|
||||||
} else {
|
} else {
|
||||||
this.name = name;
|
this.name = nameToSet;
|
||||||
this.target = target;
|
this.target = targetToSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String cleanUp(String source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dollarIndex = source.lastIndexOf('$');
|
||||||
|
return dollarIndex == -1 ? source : source.substring(dollarIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.Field#getKey()
|
* @see org.springframework.data.mongodb.core.aggregation.Field#getKey()
|
||||||
@@ -223,6 +237,15 @@ public class Fields implements Iterable<Field> {
|
|||||||
return StringUtils.hasText(this.target) ? this.target : this.name;
|
return StringUtils.hasText(this.target) ? this.target : this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.Field#isAliased()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isAliased() {
|
||||||
|
return !getName().equals(getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
@@ -231,5 +254,40 @@ public class Fields implements Iterable<Field> {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("AggregationField - name: %s, target: %s", name, target);
|
return String.format("AggregationField - name: %s, target: %s", name, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof AggregationField)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AggregationField that = (AggregationField) obj;
|
||||||
|
|
||||||
|
return this.name.equals(that.name) && ObjectUtils.nullSafeEquals(this.target, that.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
|
||||||
|
int result = 17;
|
||||||
|
|
||||||
|
result += 31 * name.hashCode();
|
||||||
|
result += 31 * ObjectUtils.nullSafeHashCode(target);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AggregationOperation} that exposes new {@link ExposedFields} that can be used for later aggregation pipeline
|
||||||
|
* {@code AggregationOperation}s.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public interface FieldsExposingAggregationOperation extends AggregationOperation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fields exposed by the {@link AggregationOperation}.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
ExposedFields getFields();
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
@@ -38,9 +38,13 @@ import com.mongodb.DBObject;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class GroupOperation extends ExposedFieldsAggregationOperationContext implements AggregationOperation {
|
public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the non-synthetic fields which are the fields of the group-id structure.
|
||||||
|
*/
|
||||||
|
private final ExposedFields idFields;
|
||||||
|
|
||||||
private final ExposedFields nonSynthecticFields;
|
|
||||||
private final List<Operation> operations;
|
private final List<Operation> operations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +54,7 @@ public class GroupOperation extends ExposedFieldsAggregationOperationContext imp
|
|||||||
*/
|
*/
|
||||||
public GroupOperation(Fields fields) {
|
public GroupOperation(Fields fields) {
|
||||||
|
|
||||||
this.nonSynthecticFields = ExposedFields.nonSynthetic(fields);
|
this.idFields = ExposedFields.nonSynthetic(fields);
|
||||||
this.operations = new ArrayList<Operation>();
|
this.operations = new ArrayList<Operation>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ public class GroupOperation extends ExposedFieldsAggregationOperationContext imp
|
|||||||
Assert.notNull(groupOperation, "GroupOperation must not be null!");
|
Assert.notNull(groupOperation, "GroupOperation must not be null!");
|
||||||
Assert.notNull(nextOperations, "NextOperations must not be null!");
|
Assert.notNull(nextOperations, "NextOperations must not be null!");
|
||||||
|
|
||||||
this.nonSynthecticFields = groupOperation.nonSynthecticFields;
|
this.idFields = groupOperation.idFields;
|
||||||
this.operations = new ArrayList<Operation>(nextOperations.size() + 1);
|
this.operations = new ArrayList<Operation>(nextOperations.size() + 1);
|
||||||
this.operations.addAll(groupOperation.operations);
|
this.operations.addAll(groupOperation.operations);
|
||||||
this.operations.addAll(nextOperations);
|
this.operations.addAll(nextOperations);
|
||||||
@@ -95,7 +99,7 @@ public class GroupOperation extends ExposedFieldsAggregationOperationContext imp
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class GroupOperationBuilder {
|
public static final class GroupOperationBuilder {
|
||||||
|
|
||||||
private final GroupOperation groupOperation;
|
private final GroupOperation groupOperation;
|
||||||
private final Operation operation;
|
private final Operation operation;
|
||||||
@@ -261,7 +265,7 @@ public class GroupOperation extends ExposedFieldsAggregationOperationContext imp
|
|||||||
@Override
|
@Override
|
||||||
public ExposedFields getFields() {
|
public ExposedFields getFields() {
|
||||||
|
|
||||||
ExposedFields fields = this.nonSynthecticFields.and(new ExposedField(Fields.UNDERSCORE_ID, true));
|
ExposedFields fields = this.idFields.and(new ExposedField(Fields.UNDERSCORE_ID, true));
|
||||||
|
|
||||||
for (Operation operation : operations) {
|
for (Operation operation : operations) {
|
||||||
fields = fields.and(operation.asField());
|
fields = fields.and(operation.asField());
|
||||||
@@ -279,16 +283,20 @@ public class GroupOperation extends ExposedFieldsAggregationOperationContext imp
|
|||||||
|
|
||||||
BasicDBObject operationObject = new BasicDBObject();
|
BasicDBObject operationObject = new BasicDBObject();
|
||||||
|
|
||||||
if (nonSynthecticFields.exposesSingleFieldOnly()) {
|
if (idFields.exposesNoNonSyntheticFields()) {
|
||||||
|
|
||||||
FieldReference reference = context.getReference(nonSynthecticFields.iterator().next());
|
operationObject.put(Fields.UNDERSCORE_ID, null);
|
||||||
|
|
||||||
|
} else if (idFields.exposesSingleNonSyntheticFieldOnly()) {
|
||||||
|
|
||||||
|
FieldReference reference = context.getReference(idFields.iterator().next());
|
||||||
operationObject.put(Fields.UNDERSCORE_ID, reference.toString());
|
operationObject.put(Fields.UNDERSCORE_ID, reference.toString());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
BasicDBObject inner = new BasicDBObject();
|
BasicDBObject inner = new BasicDBObject();
|
||||||
|
|
||||||
for (ExposedField field : nonSynthecticFields) {
|
for (ExposedField field : idFields) {
|
||||||
FieldReference reference = context.getReference(field);
|
FieldReference reference = context.getReference(field);
|
||||||
inner.put(field.getName(), reference.toString());
|
inner.put(field.getName(), reference.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -21,7 +21,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
|
||||||
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;
|
||||||
|
|
||||||
@@ -41,9 +40,11 @@ import com.mongodb.DBObject;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class ProjectionOperation extends ExposedFieldsAggregationOperationContext implements AggregationOperation {
|
public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||||
|
|
||||||
private static final List<Projection> NONE = Collections.emptyList();
|
private static final List<Projection> NONE = Collections.emptyList();
|
||||||
|
private static final String EXCLUSION_ERROR = "Exclusion of field %s not allowed. Projections by the mongodb "
|
||||||
|
+ "aggregation framework only support the exclusion of the %s field!";
|
||||||
|
|
||||||
private final List<Projection> projections;
|
private final List<Projection> projections;
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
* @param fields must not be {@literal null}.
|
* @param fields must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public ProjectionOperation(Fields fields) {
|
public ProjectionOperation(Fields fields) {
|
||||||
this(NONE, ProjectionOperationBuilder.FieldProjection.from(fields, true));
|
this(NONE, ProjectionOperationBuilder.FieldProjection.from(fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,26 +115,36 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
return new ProjectionOperationBuilder(name, this, null);
|
return new ProjectionOperationBuilder(name, this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ExpressionProjectionOperationBuilder andExpression(String expression, Object... params) {
|
||||||
|
return new ExpressionProjectionOperationBuilder(expression, this, params);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Excludes the given fields from the projection.
|
* Excludes the given fields from the projection.
|
||||||
*
|
*
|
||||||
* @param fields must not be {@literal null}.
|
* @param fieldNames must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ProjectionOperation andExclude(String... fields) {
|
public ProjectionOperation andExclude(String... fieldNames) {
|
||||||
List<FieldProjection> excludeProjections = FieldProjection.from(Fields.fields(fields), false);
|
|
||||||
|
for (String fieldName : fieldNames) {
|
||||||
|
Assert.isTrue(Fields.UNDERSCORE_ID.equals(fieldName),
|
||||||
|
String.format(EXCLUSION_ERROR, fieldName, Fields.UNDERSCORE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FieldProjection> excludeProjections = FieldProjection.from(Fields.fields(fieldNames), false);
|
||||||
return new ProjectionOperation(this.projections, excludeProjections);
|
return new ProjectionOperation(this.projections, excludeProjections);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Includes the given fields into the projection.
|
* Includes the given fields into the projection.
|
||||||
*
|
*
|
||||||
* @param fields must not be {@literal null}.
|
* @param fieldNames must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ProjectionOperation andInclude(String... fields) {
|
public ProjectionOperation andInclude(String... fieldNames) {
|
||||||
|
|
||||||
List<FieldProjection> projections = FieldProjection.from(Fields.fields(fields), true);
|
List<FieldProjection> projections = FieldProjection.from(Fields.fields(fieldNames), true);
|
||||||
return new ProjectionOperation(this.projections, projections);
|
return new ProjectionOperation(this.projections, projections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,12 +158,12 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
return new ProjectionOperation(this.projections, FieldProjection.from(fields, true));
|
return new ProjectionOperation(this.projections, FieldProjection.from(fields, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext#getFields()
|
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected ExposedFields getFields() {
|
public ExposedFields getFields() {
|
||||||
|
|
||||||
ExposedFields fields = null;
|
ExposedFields fields = null;
|
||||||
|
|
||||||
@@ -180,12 +191,133 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
return new BasicDBObject("$project", fieldObject);
|
return new BasicDBObject("$project", fieldObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for {@link ProjectionOperationBuilder}s.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
private static abstract class AbstractProjectionOperationBuilder implements AggregationOperation {
|
||||||
|
|
||||||
|
protected final Object value;
|
||||||
|
protected final ProjectionOperation operation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link AbstractProjectionOperationBuilder} fot the given value and {@link ProjectionOperation}.
|
||||||
|
*
|
||||||
|
* @param value must not be {@literal null}.
|
||||||
|
* @param operation must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public AbstractProjectionOperationBuilder(Object value, ProjectionOperation operation) {
|
||||||
|
|
||||||
|
Assert.notNull(value, "value must not be null or empty!");
|
||||||
|
Assert.notNull(operation, "ProjectionOperation must not be null!");
|
||||||
|
|
||||||
|
this.value = value;
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
|
return this.operation.toDBObject(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the finally to be applied {@link ProjectionOperation} with the given alias.
|
||||||
|
*
|
||||||
|
* @param alias will never be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract ProjectionOperation as(String alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public static class ExpressionProjectionOperationBuilder extends AbstractProjectionOperationBuilder {
|
||||||
|
|
||||||
|
private final Object[] params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionProjectionOperationBuilder} for the given value, {@link ProjectionOperation} and
|
||||||
|
* parameters.
|
||||||
|
*
|
||||||
|
* @param value must not be {@literal null}.
|
||||||
|
* @param operation must not be {@literal null}.
|
||||||
|
* @param parameters
|
||||||
|
*/
|
||||||
|
public ExpressionProjectionOperationBuilder(Object value, ProjectionOperation operation, Object[] parameters) {
|
||||||
|
|
||||||
|
super(value, operation);
|
||||||
|
this.params = parameters.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#as(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ProjectionOperation as(String alias) {
|
||||||
|
|
||||||
|
Field expressionField = Fields.field(alias, alias);
|
||||||
|
return this.operation.and(new ExpressionProjection(expressionField, this.value.toString(), params));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Projection} based on a SpEL expression.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
static class ExpressionProjection extends Projection {
|
||||||
|
|
||||||
|
private static final SpelExpressionTransformer TRANSFORMER = new SpelExpressionTransformer();
|
||||||
|
|
||||||
|
private final String expression;
|
||||||
|
private final Object[] params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionProjection} for the given field, SpEL expression and parameters.
|
||||||
|
*
|
||||||
|
* @param field must not be {@literal null}.
|
||||||
|
* @param expression must not be {@literal null} or empty.
|
||||||
|
* @param parameters must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public ExpressionProjection(Field field, String expression, Object[] parameters) {
|
||||||
|
|
||||||
|
super(field);
|
||||||
|
|
||||||
|
Assert.hasText(expression, "Expression must not be null!");
|
||||||
|
Assert.notNull(parameters, "Parameters must not be null!");
|
||||||
|
|
||||||
|
this.expression = expression;
|
||||||
|
this.params = parameters.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
|
return new BasicDBObject(getExposedField().getName(), TRANSFORMER.transform(expression, context, params));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for {@link ProjectionOperation}s on a field.
|
* Builder for {@link ProjectionOperation}s on a field.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public static class ProjectionOperationBuilder implements AggregationOperation {
|
public static class ProjectionOperationBuilder extends AbstractProjectionOperationBuilder {
|
||||||
|
|
||||||
|
private static final String NUMBER_NOT_NULL = "Number 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 ProjectionOperation operation;
|
||||||
@@ -200,9 +332,7 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
* @param previousProjection the previous operation projection, may be {@literal null}.
|
* @param previousProjection the previous operation projection, may be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder(String name, ProjectionOperation operation, OperationProjection previousProjection) {
|
public ProjectionOperationBuilder(String name, ProjectionOperation operation, OperationProjection previousProjection) {
|
||||||
|
super(name, operation);
|
||||||
Assert.hasText(name, "Field name must not be null or empty!");
|
|
||||||
Assert.notNull(operation, "ProjectionOperation must not be null!");
|
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
@@ -237,10 +367,11 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
* @param string
|
* @param string
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public ProjectionOperation as(String alias) {
|
public ProjectionOperation as(String alias) {
|
||||||
|
|
||||||
if (previousProjection != null) {
|
if (this.previousProjection != null) {
|
||||||
return this.operation.andReplaceLastOneWith(previousProjection.withAlias(alias));
|
return this.operation.andReplaceLastOneWith(this.previousProjection.withAlias(alias));
|
||||||
} else {
|
} else {
|
||||||
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
||||||
}
|
}
|
||||||
@@ -254,10 +385,22 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder plus(Number number) {
|
public ProjectionOperationBuilder plus(Number number) {
|
||||||
|
|
||||||
Assert.notNull(number, "Number must not be null!");
|
Assert.notNull(number, NUMBER_NOT_NULL);
|
||||||
return project("add", number);
|
return project("add", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an {@code $add} expression that adds the value of the given field to the previously mentioned field.
|
||||||
|
*
|
||||||
|
* @param fieldReference
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder plus(String fieldReference) {
|
||||||
|
|
||||||
|
Assert.notNull(fieldReference, "Field reference must not be null!");
|
||||||
|
return project("add", Fields.field(fieldReference));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an {@code $subtract} expression that subtracts the given number to the previously mentioned field.
|
* Generates an {@code $subtract} expression that subtracts the given number to the previously mentioned field.
|
||||||
*
|
*
|
||||||
@@ -270,6 +413,19 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
return project("subtract", number);
|
return project("subtract", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an {@code $subtract} expression that subtracts the value of the given field to the previously mentioned
|
||||||
|
* field.
|
||||||
|
*
|
||||||
|
* @param fieldReference
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder minus(String fieldReference) {
|
||||||
|
|
||||||
|
Assert.notNull(fieldReference, FIELD_REFERENCE_NOT_NULL);
|
||||||
|
return project("subtract", Fields.field(fieldReference));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an {@code $multiply} expression that multiplies the given number with the previously mentioned field.
|
* Generates an {@code $multiply} expression that multiplies the given number with the previously mentioned field.
|
||||||
*
|
*
|
||||||
@@ -278,10 +434,23 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder multiply(Number number) {
|
public ProjectionOperationBuilder multiply(Number number) {
|
||||||
|
|
||||||
Assert.notNull(number, "Number must not be null!");
|
Assert.notNull(number, NUMBER_NOT_NULL);
|
||||||
return project("multiply", number);
|
return project("multiply", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an {@code $multiply} expression that multiplies the value of the given field with the previously
|
||||||
|
* mentioned field.
|
||||||
|
*
|
||||||
|
* @param fieldReference
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder multiply(String fieldReference) {
|
||||||
|
|
||||||
|
Assert.notNull(fieldReference, FIELD_REFERENCE_NOT_NULL);
|
||||||
|
return project("multiply", Fields.field(fieldReference));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an {@code $divide} expression that divides the previously mentioned field by the given number.
|
* Generates an {@code $divide} expression that divides the previously mentioned field by the given number.
|
||||||
*
|
*
|
||||||
@@ -290,11 +459,24 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder divide(Number number) {
|
public ProjectionOperationBuilder divide(Number number) {
|
||||||
|
|
||||||
Assert.notNull(number, "Number must not be null!");
|
Assert.notNull(number, FIELD_REFERENCE_NOT_NULL);
|
||||||
Assert.isTrue(Math.abs(number.intValue()) != 0, "Number must not be zero!");
|
Assert.isTrue(Math.abs(number.intValue()) != 0, "Number must not be zero!");
|
||||||
return project("divide", number);
|
return project("divide", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an {@code $divide} expression that divides the value of the given field by the previously mentioned
|
||||||
|
* field.
|
||||||
|
*
|
||||||
|
* @param fieldReference
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder divide(String fieldReference) {
|
||||||
|
|
||||||
|
Assert.notNull(fieldReference, FIELD_REFERENCE_NOT_NULL);
|
||||||
|
return project("divide", Fields.field(fieldReference));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an {@code $mod} expression that divides the previously mentioned field by the given number and returns
|
* Generates an {@code $mod} expression that divides the previously mentioned field by the given number and returns
|
||||||
* the remainder.
|
* the remainder.
|
||||||
@@ -304,12 +486,26 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
*/
|
*/
|
||||||
public ProjectionOperationBuilder mod(Number number) {
|
public ProjectionOperationBuilder mod(Number number) {
|
||||||
|
|
||||||
Assert.notNull(number, "Number must not be null!");
|
Assert.notNull(number, NUMBER_NOT_NULL);
|
||||||
Assert.isTrue(Math.abs(number.intValue()) != 0, "Number must not be zero!");
|
Assert.isTrue(Math.abs(number.intValue()) != 0, "Number must not be zero!");
|
||||||
return project("mod", number);
|
return project("mod", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
|
* Generates an {@code $mod} expression that divides the value of the given field by the previously mentioned field
|
||||||
|
* and returns the remainder.
|
||||||
|
*
|
||||||
|
* @param fieldReference
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ProjectionOperationBuilder mod(String fieldReference) {
|
||||||
|
|
||||||
|
Assert.notNull(fieldReference, FIELD_REFERENCE_NOT_NULL);
|
||||||
|
return project("mod", Fields.field(fieldReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -362,6 +558,7 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
* A {@link FieldProjection} to map a result of a previous {@link AggregationOperation} to a new field.
|
* A {@link FieldProjection} to map a result of a previous {@link AggregationOperation} to a new field.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
static class FieldProjection extends Projection {
|
static class FieldProjection extends Projection {
|
||||||
|
|
||||||
@@ -386,20 +583,31 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to easily create {@link FieldProjection}s for the given {@link Fields}. Fields are projected as
|
||||||
|
* references with their given name. A field {@code foo} will be projected as: {@code foo : 1 } .
|
||||||
|
*
|
||||||
|
* @param fields the {@link Fields} to in- or exclude, must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<? extends Projection> from(Fields fields) {
|
||||||
|
return from(fields, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to easily create {@link FieldProjection}s for the given {@link Fields}.
|
* Factory method to easily create {@link FieldProjection}s for the given {@link Fields}.
|
||||||
*
|
*
|
||||||
* @param fields the {@link Fields} to in- or exclude, must not be {@literal null}.
|
* @param fields the {@link Fields} to in- or exclude, must not be {@literal null}.
|
||||||
* @param include whether to include or exclude the fields.
|
* @param value to use for the given field.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static List<FieldProjection> from(Fields fields, boolean include) {
|
public static List<FieldProjection> from(Fields fields, Object value) {
|
||||||
|
|
||||||
Assert.notNull(fields, "Fields must not be null!");
|
Assert.notNull(fields, "Fields must not be null!");
|
||||||
List<FieldProjection> projections = new ArrayList<FieldProjection>();
|
List<FieldProjection> projections = new ArrayList<FieldProjection>();
|
||||||
|
|
||||||
for (Field field : fields) {
|
for (Field field : fields) {
|
||||||
projections.add(new FieldProjection(field, include ? null : 0));
|
projections.add(new FieldProjection(field, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return projections;
|
return projections;
|
||||||
@@ -411,13 +619,24 @@ public class ProjectionOperation extends ExposedFieldsAggregationOperationContex
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DBObject toDBObject(AggregationOperationContext context) {
|
public DBObject toDBObject(AggregationOperationContext context) {
|
||||||
|
return new BasicDBObject(field.getName(), renderFieldValue(context));
|
||||||
|
}
|
||||||
|
|
||||||
if (value != null) {
|
private Object renderFieldValue(AggregationOperationContext context) {
|
||||||
return new BasicDBObject(field.getName(), value);
|
|
||||||
|
// implicit reference or explicit include?
|
||||||
|
if (value == null || Boolean.TRUE.equals(value)) {
|
||||||
|
|
||||||
|
// check whether referenced field exists in the context
|
||||||
|
return context.getReference(field).getReferenceValue();
|
||||||
|
|
||||||
|
} else if (Boolean.FALSE.equals(value)) {
|
||||||
|
|
||||||
|
// render field as excluded
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldReference reference = context.getReference(field.getTarget());
|
return value;
|
||||||
return new BasicDBObject(field.getName(), reference.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,513 @@
|
|||||||
|
/*
|
||||||
|
* 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.aggregation;
|
||||||
|
|
||||||
|
import static org.springframework.data.mongodb.util.DBObjectUtils.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.data.mongodb.core.spel.ExpressionNode;
|
||||||
|
import org.springframework.data.mongodb.core.spel.ExpressionTransformationContextSupport;
|
||||||
|
import org.springframework.data.mongodb.core.spel.LiteralNode;
|
||||||
|
import org.springframework.data.mongodb.core.spel.MethodReferenceNode;
|
||||||
|
import org.springframework.data.mongodb.core.spel.OperatorNode;
|
||||||
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
import org.springframework.expression.spel.SpelNode;
|
||||||
|
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||||
|
import org.springframework.expression.spel.ast.CompoundExpression;
|
||||||
|
import org.springframework.expression.spel.ast.Indexer;
|
||||||
|
import org.springframework.expression.spel.ast.InlineList;
|
||||||
|
import org.springframework.expression.spel.ast.PropertyOrFieldReference;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpression;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.NumberUtils;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the AST of a SpEL expression as a MongoDB Aggregation Framework projection expression.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||||
|
|
||||||
|
// TODO: remove explicit usage of a configuration once SPR-11031 gets fixed
|
||||||
|
private static final SpelParserConfiguration CONFIG = new SpelParserConfiguration(false, false);
|
||||||
|
private static final SpelExpressionParser PARSER = new SpelExpressionParser(CONFIG);
|
||||||
|
private final List<ExpressionNodeConversion<? extends ExpressionNode>> conversions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SpelExpressionTransformer}.
|
||||||
|
*/
|
||||||
|
public SpelExpressionTransformer() {
|
||||||
|
|
||||||
|
List<ExpressionNodeConversion<? extends ExpressionNode>> conversions = new ArrayList<ExpressionNodeConversion<? extends ExpressionNode>>();
|
||||||
|
conversions.add(new OperatorNodeConversion(this));
|
||||||
|
conversions.add(new LiteralNodeConversion(this));
|
||||||
|
conversions.add(new IndexerNodeConversion(this));
|
||||||
|
conversions.add(new InlineListNodeConversion(this));
|
||||||
|
conversions.add(new PropertyOrFieldReferenceNodeConversion(this));
|
||||||
|
conversions.add(new CompoundExpressionNodeConversion(this));
|
||||||
|
conversions.add(new MethodReferenceNodeConversion(this));
|
||||||
|
|
||||||
|
this.conversions = Collections.unmodifiableList(conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the given SpEL expression to a corresponding MongoDB expression against the given
|
||||||
|
* {@link AggregationOperationContext} {@code context}.
|
||||||
|
* <p>
|
||||||
|
* Exposes the given @{code params} as <code>[0] ... [n]</code>.
|
||||||
|
*
|
||||||
|
* @param expression must not be {@literal null}
|
||||||
|
* @param context must not be {@literal null}
|
||||||
|
* @param params must not be {@literal null}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object transform(String expression, AggregationOperationContext context, Object... params) {
|
||||||
|
|
||||||
|
Assert.notNull(expression, "Expression must not be null!");
|
||||||
|
Assert.notNull(context, "AggregationOperationContext must not be null!");
|
||||||
|
Assert.notNull(params, "Parameters must not be null!");
|
||||||
|
|
||||||
|
SpelExpression spelExpression = (SpelExpression) PARSER.parseExpression(expression);
|
||||||
|
ExpressionState state = new ExpressionState(new StandardEvaluationContext(params), CONFIG);
|
||||||
|
ExpressionNode node = ExpressionNode.from(spelExpression.getAST(), state);
|
||||||
|
|
||||||
|
return transform(new AggregationExpressionTransformationContext<ExpressionNode>(node, null, null, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.spel.ExpressionTransformer#transform(org.springframework.data.mongodb.core.spel.ExpressionTransformationContextSupport)
|
||||||
|
*/
|
||||||
|
public Object transform(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
return lookupConversionFor(context.getCurrentNode()).convert(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an appropriate {@link ExpressionNodeConversion} for the given {@code node}. Throws an
|
||||||
|
* {@link IllegalArgumentException} if no conversion could be found.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @return the appropriate {@link ExpressionNodeConversion} for the given {@link ExpressionNode}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private ExpressionNodeConversion<ExpressionNode> lookupConversionFor(ExpressionNode node) {
|
||||||
|
|
||||||
|
for (ExpressionNodeConversion<? extends ExpressionNode> candidate : conversions) {
|
||||||
|
if (candidate.supports(node)) {
|
||||||
|
return (ExpressionNodeConversion<ExpressionNode>) candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unsupported Element: " + node + " Type: " + node.getClass()
|
||||||
|
+ " You probably have a syntax error in your SpEL expression!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for {@link SpelNode} to (Db)-object conversions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static abstract class ExpressionNodeConversion<T extends ExpressionNode> implements
|
||||||
|
AggregationExpressionTransformer {
|
||||||
|
|
||||||
|
private final AggregationExpressionTransformer transformer;
|
||||||
|
private final Class<? extends ExpressionNode> nodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionNodeConversion}.
|
||||||
|
*
|
||||||
|
* @param transformer must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ExpressionNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
|
||||||
|
Assert.notNull(transformer, "Transformer must not be null!");
|
||||||
|
|
||||||
|
this.nodeType = (Class<? extends ExpressionNode>) GenericTypeResolver.resolveTypeArgument(this.getClass(),
|
||||||
|
ExpressionNodeConversion.class);
|
||||||
|
this.transformer = transformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current conversion supports the given {@link ExpressionNode}. By default we will match the
|
||||||
|
* node type against the genric type the subclass types the type parameter to.
|
||||||
|
*
|
||||||
|
* @param node will never be {@literal null}.
|
||||||
|
* @return true if {@literal this} conversion can be applied to the given {@code node}.
|
||||||
|
*/
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return nodeType.equals(node.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the transformation for the given {@link ExpressionNode} and the given current context.
|
||||||
|
*
|
||||||
|
* @param node must not be {@literal null}.
|
||||||
|
* @param context must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Object transform(ExpressionNode node, AggregationExpressionTransformationContext<?> context) {
|
||||||
|
|
||||||
|
Assert.notNull(node, "ExpressionNode must not be null!");
|
||||||
|
Assert.notNull(context, "AggregationExpressionTransformationContext must not be null!");
|
||||||
|
|
||||||
|
return transform(node, context.getParentNode(), null, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the transformation with the given new {@link ExpressionNode}, new parent node, the current operation and
|
||||||
|
* the previous context.
|
||||||
|
*
|
||||||
|
* @param node must not be {@literal null}.
|
||||||
|
* @param parent
|
||||||
|
* @param operation
|
||||||
|
* @param context must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Object transform(ExpressionNode node, ExpressionNode parent, DBObject operation,
|
||||||
|
AggregationExpressionTransformationContext<?> context) {
|
||||||
|
|
||||||
|
Assert.notNull(node, "ExpressionNode must not be null!");
|
||||||
|
Assert.notNull(context, "AggregationExpressionTransformationContext must not be null!");
|
||||||
|
|
||||||
|
return transform(new AggregationExpressionTransformationContext<ExpressionNode>(node, parent, operation,
|
||||||
|
context.getAggregationContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#transform(org.springframework.data.mongodb.core.aggregation.AggregationExpressionTransformer.AggregationExpressionTransformationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object transform(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
return transformer.transform(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the actual conversion from {@link SpelNode} to the corresponding representation for MongoDB.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract Object convert(AggregationExpressionTransformationContext<T> context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts arithmetic operations.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
private static class OperatorNodeConversion extends ExpressionNodeConversion<OperatorNode> {
|
||||||
|
|
||||||
|
public OperatorNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<OperatorNode> context) {
|
||||||
|
|
||||||
|
OperatorNode currentNode = context.getCurrentNode();
|
||||||
|
|
||||||
|
DBObject operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary(context, currentNode);
|
||||||
|
Object leftResult = transform(currentNode.getLeft(), currentNode, operationObject, context);
|
||||||
|
|
||||||
|
if (currentNode.isUnaryMinus()) {
|
||||||
|
return convertUnaryMinusOp(context, leftResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we deliberately ignore the RHS result
|
||||||
|
transform(currentNode.getRight(), currentNode, operationObject, context);
|
||||||
|
|
||||||
|
return operationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DBObject createOperationObjectAndAddToPreviousArgumentsIfNecessary(
|
||||||
|
AggregationExpressionTransformationContext<OperatorNode> context, OperatorNode currentNode) {
|
||||||
|
|
||||||
|
DBObject nextDbObject = new BasicDBObject(currentNode.getMongoOperator(), new BasicDBList());
|
||||||
|
|
||||||
|
if (!context.hasPreviousOperation()) {
|
||||||
|
return nextDbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.parentIsSameOperation()) {
|
||||||
|
|
||||||
|
// same operator applied in a row e.g. 1 + 2 + 3 carry on with the operation and render as $add: [1, 2 ,3]
|
||||||
|
nextDbObject = context.getPreviousOperationObject();
|
||||||
|
} else if (!currentNode.isUnaryOperator()) {
|
||||||
|
|
||||||
|
// different operator -> add context object for next level to list if arguments of previous expression
|
||||||
|
context.addToPreviousOperation(nextDbObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextDbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object convertUnaryMinusOp(ExpressionTransformationContextSupport<OperatorNode> context, Object leftResult) {
|
||||||
|
|
||||||
|
Object result = leftResult instanceof Number ? leftResult
|
||||||
|
: new BasicDBObject("$multiply", dbList(-1, leftResult));
|
||||||
|
|
||||||
|
if (leftResult != null && context.hasPreviousOperation()) {
|
||||||
|
context.addToPreviousOperation(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#supports(java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isMathematicalOperation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts indexed expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class IndexerNodeConversion extends ExpressionNodeConversion<ExpressionNode> {
|
||||||
|
|
||||||
|
public IndexerNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
return context.addToPreviousOrReturn(context.getCurrentNode().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isOfType(Indexer.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts in-line list expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
private static class InlineListNodeConversion extends ExpressionNodeConversion<ExpressionNode> {
|
||||||
|
|
||||||
|
public InlineListNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
|
||||||
|
ExpressionNode currentNode = context.getCurrentNode();
|
||||||
|
|
||||||
|
if (!currentNode.hasChildren()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just take the first item
|
||||||
|
return transform(currentNode.getChild(0), currentNode, null, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isOfType(InlineList.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts property or field reference expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class PropertyOrFieldReferenceNodeConversion extends ExpressionNodeConversion<ExpressionNode> {
|
||||||
|
|
||||||
|
public PropertyOrFieldReferenceNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#convert(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionTransformationContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
|
||||||
|
String fieldReference = context.getFieldReference().toString();
|
||||||
|
return context.addToPreviousOrReturn(fieldReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isOfType(PropertyOrFieldReference.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts literal expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class LiteralNodeConversion extends ExpressionNodeConversion<LiteralNode> {
|
||||||
|
|
||||||
|
public LiteralNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<LiteralNode> context) {
|
||||||
|
|
||||||
|
LiteralNode node = context.getCurrentNode();
|
||||||
|
Object value = node.getValue();
|
||||||
|
|
||||||
|
if (context.hasPreviousOperation()) {
|
||||||
|
|
||||||
|
if (node.isUnaryMinus(context.getParentNode())) {
|
||||||
|
// unary minus operator
|
||||||
|
return NumberUtils.convertNumberToTargetClass(((Number) value).doubleValue() * -1,
|
||||||
|
(Class<Number>) value.getClass()); // retain type, e.g. int to -int
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.addToPreviousOperation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#supports(org.springframework.expression.spel.SpelNode)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isLiteral();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts method reference expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class MethodReferenceNodeConversion extends ExpressionNodeConversion<MethodReferenceNode> {
|
||||||
|
|
||||||
|
public MethodReferenceNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<MethodReferenceNode> context) {
|
||||||
|
|
||||||
|
MethodReferenceNode node = context.getCurrentNode();
|
||||||
|
List<Object> args = new ArrayList<Object>();
|
||||||
|
|
||||||
|
for (ExpressionNode childNode : node) {
|
||||||
|
args.add(transform(childNode, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.addToPreviousOrReturn(new BasicDBObject(node.getMethodName(), dbList(args.toArray())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ExpressionNodeConversion} that converts method compound expressions.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class CompoundExpressionNodeConversion extends ExpressionNodeConversion<ExpressionNode> {
|
||||||
|
|
||||||
|
public CompoundExpressionNodeConversion(AggregationExpressionTransformer transformer) {
|
||||||
|
super(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Object convert(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||||
|
|
||||||
|
ExpressionNode currentNode = context.getCurrentNode();
|
||||||
|
|
||||||
|
if (currentNode.hasfirstChildNotOfType(Indexer.class)) {
|
||||||
|
// we have a property path expression like: foo.bar -> render as reference
|
||||||
|
return context.addToPreviousOrReturn(context.getFieldReference().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.addToPreviousOrReturn(currentNode.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean supports(ExpressionNode node) {
|
||||||
|
return node.isOfType(CompoundExpression.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,14 +71,14 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
|
|||||||
return mapper.getMappedObject(dbObject, mappingContext.getPersistentEntity(type));
|
return mapper.getMappedObject(dbObject, mappingContext.getPersistentEntity(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.ExposedFields.AvailableField)
|
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.Field)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(Field field) {
|
public FieldReference getReference(Field field) {
|
||||||
|
|
||||||
PropertyPath.from(field.getName(), type);
|
PropertyPath.from(field.getTarget(), type);
|
||||||
return getReferenceFor(field);
|
return getReferenceFor(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +88,16 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(String name) {
|
public FieldReference getReference(String name) {
|
||||||
PropertyPath path = PropertyPath.from(name, type);
|
return getReferenceFor(field(name));
|
||||||
|
|
||||||
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
|
|
||||||
|
|
||||||
return getReferenceFor(field(path.getLeafProperty().getSegment(),
|
|
||||||
propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldReference getReferenceFor(Field field) {
|
private FieldReference getReferenceFor(Field field) {
|
||||||
return new FieldReference(new ExposedField(field, true));
|
|
||||||
|
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(
|
||||||
|
field.getTarget(), type);
|
||||||
|
Field mappedField = field(propertyPath.getLeafProperty().getName(),
|
||||||
|
propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE));
|
||||||
|
|
||||||
|
return new FieldReference(new ExposedField(mappedField, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import com.mongodb.DBObject;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class UnwindOperation extends ExposedFieldsAggregationOperationContext implements AggregationOperation {
|
public class UnwindOperation implements AggregationOperation {
|
||||||
|
|
||||||
private final ExposedField field;
|
private final ExposedField field;
|
||||||
|
|
||||||
@@ -44,15 +44,6 @@ public class UnwindOperation extends ExposedFieldsAggregationOperationContext im
|
|||||||
this.field = new ExposedField(field, true);
|
this.field = new ExposedField(field, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext#getFields()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected ExposedFields getFields() {
|
|
||||||
return ExposedFields.from(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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,12 +17,14 @@ 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.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
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.ConcurrentMap;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -39,6 +41,7 @@ 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.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;
|
||||||
@@ -54,6 +57,7 @@ import org.springframework.util.Assert;
|
|||||||
* .
|
* .
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class CustomConversions {
|
public class CustomConversions {
|
||||||
|
|
||||||
@@ -65,7 +69,7 @@ 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 Map<Class<?>, HashMap<Class<?>, CacheValue>> cache;
|
private final ConcurrentMap<ConvertiblePair, CacheValue> customReadTargetTypes;
|
||||||
|
|
||||||
private final List<Object> converters;
|
private final List<Object> converters;
|
||||||
|
|
||||||
@@ -85,26 +89,34 @@ public class CustomConversions {
|
|||||||
|
|
||||||
Assert.notNull(converters);
|
Assert.notNull(converters);
|
||||||
|
|
||||||
this.readingPairs = new HashSet<ConvertiblePair>();
|
this.readingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||||
this.writingPairs = new HashSet<ConvertiblePair>();
|
this.writingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||||
this.customSimpleTypes = new HashSet<Class<?>>();
|
this.customSimpleTypes = new HashSet<Class<?>>();
|
||||||
this.cache = new HashMap<Class<?>, HashMap<Class<?>, CacheValue>>();
|
this.customReadTargetTypes = new ConcurrentHashMap<GenericConverter.ConvertiblePair, CacheValue>();
|
||||||
|
|
||||||
this.converters = new ArrayList<Object>();
|
List<Object> toRegister = new ArrayList<Object>();
|
||||||
this.converters.add(CustomToStringConverter.INSTANCE);
|
|
||||||
this.converters.add(BigDecimalToStringConverter.INSTANCE);
|
|
||||||
this.converters.add(StringToBigDecimalConverter.INSTANCE);
|
|
||||||
this.converters.add(BigIntegerToStringConverter.INSTANCE);
|
|
||||||
this.converters.add(StringToBigIntegerConverter.INSTANCE);
|
|
||||||
this.converters.add(URLToStringConverter.INSTANCE);
|
|
||||||
this.converters.add(StringToURLConverter.INSTANCE);
|
|
||||||
this.converters.addAll(JodaTimeConverters.getConvertersToRegister());
|
|
||||||
this.converters.addAll(converters);
|
|
||||||
|
|
||||||
for (Object c : this.converters) {
|
// Add user provided converters to make sure they can override the defaults
|
||||||
|
toRegister.addAll(converters);
|
||||||
|
toRegister.add(CustomToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(BigDecimalToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(StringToBigDecimalConverter.INSTANCE);
|
||||||
|
toRegister.add(BigIntegerToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(StringToBigIntegerConverter.INSTANCE);
|
||||||
|
toRegister.add(URLToStringConverter.INSTANCE);
|
||||||
|
toRegister.add(StringToURLConverter.INSTANCE);
|
||||||
|
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
||||||
|
|
||||||
|
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
||||||
|
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
||||||
|
|
||||||
|
for (Object c : toRegister) {
|
||||||
registerConversion(c);
|
registerConversion(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collections.reverse(toRegister);
|
||||||
|
|
||||||
|
this.converters = Collections.unmodifiableList(toRegister);
|
||||||
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, MongoSimpleTypes.HOLDER);
|
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, MongoSimpleTypes.HOLDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,25 +204,25 @@ public class CustomConversions {
|
|||||||
*
|
*
|
||||||
* @param pair
|
* @param pair
|
||||||
*/
|
*/
|
||||||
private void register(ConverterRegistration context) {
|
private void register(ConverterRegistration converterRegistration) {
|
||||||
|
|
||||||
ConvertiblePair pair = context.getConvertiblePair();
|
ConvertiblePair pair = converterRegistration.getConvertiblePair();
|
||||||
|
|
||||||
if (context.isReading()) {
|
if (converterRegistration.isReading()) {
|
||||||
|
|
||||||
readingPairs.add(pair);
|
readingPairs.add(pair);
|
||||||
|
|
||||||
if (LOG.isWarnEnabled() && !context.isSimpleSourceType()) {
|
if (LOG.isWarnEnabled() && !converterRegistration.isSimpleSourceType()) {
|
||||||
LOG.warn(String.format(READ_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
|
LOG.warn(String.format(READ_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.isWriting()) {
|
if (converterRegistration.isWriting()) {
|
||||||
|
|
||||||
writingPairs.add(pair);
|
writingPairs.add(pair);
|
||||||
customSimpleTypes.add(pair.getSourceType());
|
customSimpleTypes.add(pair.getSourceType());
|
||||||
|
|
||||||
if (LOG.isWarnEnabled() && !context.isSimpleTargetType()) {
|
if (LOG.isWarnEnabled() && !converterRegistration.isSimpleTargetType()) {
|
||||||
LOG.warn(String.format(WRITE_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
|
LOG.warn(String.format(WRITE_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,11 +232,11 @@ public class CustomConversions {
|
|||||||
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
|
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
|
||||||
* type into a Mongo native one.
|
* type into a Mongo native one.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Class<?> getCustomWriteTarget(Class<?> source) {
|
public Class<?> getCustomWriteTarget(Class<?> sourceType) {
|
||||||
return getCustomWriteTarget(source, null);
|
return getCustomWriteTarget(sourceType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -232,71 +244,78 @@ public class CustomConversions {
|
|||||||
* oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the
|
* oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the
|
||||||
* first target type matching or {@literal null} if no conversion can be found.
|
* first target type matching or {@literal null} if no conversion can be found.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @param expectedTargetType
|
* @param requestedTargetType
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Class<?> getCustomWriteTarget(Class<?> source, Class<?> expectedTargetType) {
|
public Class<?> getCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
Assert.notNull(source);
|
|
||||||
return getCustomTarget(source, expectedTargetType, writingPairs);
|
Assert.notNull(sourceType);
|
||||||
|
|
||||||
|
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 write into a Mongo native type. The returned type might
|
||||||
* be a subclass oth the given expected type though.
|
* be a subclass of the given expected type though.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomWriteTarget(Class<?> source) {
|
public boolean hasCustomWriteTarget(Class<?> sourceType) {
|
||||||
return hasCustomWriteTarget(source, null);
|
|
||||||
|
Assert.notNull(sourceType);
|
||||||
|
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 write an object of the given source type into an object
|
||||||
* of the given Mongo native target type.
|
* of the given Mongo native target type.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}.
|
* @param sourceType must not be {@literal null}.
|
||||||
* @param expectedTargetType
|
* @param requestedTargetType
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomWriteTarget(Class<?> source, Class<?> expectedTargetType) {
|
public boolean hasCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
return getCustomWriteTarget(source, expectedTargetType) != null;
|
|
||||||
|
Assert.notNull(sourceType);
|
||||||
|
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 read the given source into the given target type.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}
|
* @param sourceType must not be {@literal null}
|
||||||
* @param expectedTargetType must not be {@literal null}
|
* @param requestedTargetType must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
public boolean hasCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
|
|
||||||
Assert.notNull(source);
|
Assert.notNull(sourceType);
|
||||||
Assert.notNull(expectedTargetType);
|
Assert.notNull(requestedTargetType);
|
||||||
|
|
||||||
return getCustomReadTarget(source, expectedTargetType) != null;
|
return getCustomReadTarget(sourceType, requestedTargetType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
|
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
|
||||||
* checks assignabilty of the target type if one is given.
|
* checks assignability of the target type if one is given.
|
||||||
*
|
*
|
||||||
* @param source must not be {@literal null}
|
* @param sourceType must not be {@literal null}.
|
||||||
* @param expectedTargetType
|
* @param requestedTargetType can be {@literal null}.
|
||||||
* @param pairs must not be {@literal null}
|
* @param pairs must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static Class<?> getCustomTarget(Class<?> source, Class<?> expectedTargetType, Iterable<ConvertiblePair> pairs) {
|
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
|
||||||
|
Iterable<ConvertiblePair> pairs) {
|
||||||
|
|
||||||
Assert.notNull(source);
|
Assert.notNull(sourceType);
|
||||||
Assert.notNull(pairs);
|
Assert.notNull(pairs);
|
||||||
|
|
||||||
for (ConvertiblePair typePair : pairs) {
|
for (ConvertiblePair typePair : pairs) {
|
||||||
if (typePair.getSourceType().isAssignableFrom(source)) {
|
if (typePair.getSourceType().isAssignableFrom(sourceType)) {
|
||||||
Class<?> targetType = typePair.getTargetType();
|
Class<?> targetType = typePair.getTargetType();
|
||||||
if (expectedTargetType == null || targetType.isAssignableFrom(expectedTargetType)) {
|
if (requestedTargetType == null || targetType.isAssignableFrom(requestedTargetType)) {
|
||||||
return targetType;
|
return targetType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,27 +324,33 @@ public class CustomConversions {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> getCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
/**
|
||||||
|
* 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(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||||
|
|
||||||
Class<?> type = expectedTargetType == null ? PlaceholderType.class : expectedTargetType;
|
Assert.notNull(sourceType);
|
||||||
|
|
||||||
Map<Class<?>, CacheValue> map;
|
if (requestedTargetType == null) {
|
||||||
CacheValue toReturn;
|
return null;
|
||||||
|
|
||||||
if ((map = cache.get(source)) == null || (toReturn = map.get(type)) == null) {
|
|
||||||
|
|
||||||
Class<?> target = getCustomTarget(source, type, readingPairs);
|
|
||||||
|
|
||||||
if (cache.get(source) == null) {
|
|
||||||
cache.put(source, new HashMap<Class<?>, CacheValue>());
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Class<?>, CacheValue> value = cache.get(source);
|
|
||||||
toReturn = target == null ? CacheValue.NULL : new CacheValue(target);
|
|
||||||
value.put(type, toReturn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn.clazz;
|
ConvertiblePair lookupKey = new ConvertiblePair(sourceType, requestedTargetType);
|
||||||
|
CacheValue readTargetTypeValue = customReadTargetTypes.get(lookupKey);
|
||||||
|
|
||||||
|
if (readTargetTypeValue != null) {
|
||||||
|
return readTargetTypeValue.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
readTargetTypeValue = CacheValue.of(getCustomTarget(sourceType, requestedTargetType, readingPairs));
|
||||||
|
CacheValue cacheValue = customReadTargetTypes.putIfAbsent(lookupKey, readTargetTypeValue);
|
||||||
|
|
||||||
|
return cacheValue != null ? cacheValue.getType() : readTargetTypeValue.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
@@ -334,8 +359,10 @@ public class CustomConversions {
|
|||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||||
|
|
||||||
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
|
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
|
||||||
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
|
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
|
||||||
|
|
||||||
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
|
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,29 +371,29 @@ public class CustomConversions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Placeholder type to allow registering not-found values in the converter cache.
|
|
||||||
*
|
|
||||||
* @author Patryk Wasik
|
|
||||||
* @author Oliver Gierke
|
|
||||||
*/
|
|
||||||
private static class PlaceholderType {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper to safely store {@literal null} values in the type cache.
|
* Wrapper to safely store {@literal null} values in the type cache.
|
||||||
*
|
*
|
||||||
* @author Patryk Wasik
|
* @author Patryk Wasik
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
private static class CacheValue {
|
private static class CacheValue {
|
||||||
|
|
||||||
public static final CacheValue NULL = new CacheValue(null);
|
private static final CacheValue ABSENT = new CacheValue(null);
|
||||||
private final Class<?> clazz;
|
|
||||||
|
|
||||||
public CacheValue(Class<?> clazz) {
|
private final Class<?> type;
|
||||||
this.clazz = clazz;
|
|
||||||
|
public CacheValue(Class<?> type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CacheValue of(Class<?> type) {
|
||||||
|
return type == null ? ABSENT : new CacheValue(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper value object for a {@link BasicDBObject} to be able to access raw values by {@link MongoPersistentProperty}
|
||||||
|
* references. The accessors will transparently resolve nested document values that a {@link MongoPersistentProperty}
|
||||||
|
* might refer to through a path expression in field names.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
class DBObjectAccessor {
|
||||||
|
|
||||||
|
private final DBObject dbObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DBObjectAccessor} for the given {@link DBObject}.
|
||||||
|
*
|
||||||
|
* @param dbObject must be a {@link BasicDBObject} effectively, must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public DBObjectAccessor(DBObject dbObject) {
|
||||||
|
|
||||||
|
Assert.notNull(dbObject, "DBObject must not be null!");
|
||||||
|
Assert.isInstanceOf(BasicDBObject.class, dbObject, "Given DBObject must be a BasicDBObject!");
|
||||||
|
|
||||||
|
this.dbObject = dbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the given value into the backing {@link DBObject} based on the coordinates defined through the given
|
||||||
|
* {@link MongoPersistentProperty}. By default this will be the plain field name. But field names might also consist
|
||||||
|
* of path traversals so we might need to create intermediate {@link BasicDBObject}s.
|
||||||
|
*
|
||||||
|
* @param prop must not be {@literal null}.
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void put(MongoPersistentProperty prop, Object value) {
|
||||||
|
|
||||||
|
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
|
||||||
|
String fieldName = prop.getFieldName();
|
||||||
|
|
||||||
|
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||||
|
DBObject dbObject = this.dbObject;
|
||||||
|
|
||||||
|
while (parts.hasNext()) {
|
||||||
|
|
||||||
|
String part = parts.next();
|
||||||
|
|
||||||
|
if (parts.hasNext()) {
|
||||||
|
BasicDBObject nestedDbObject = new BasicDBObject();
|
||||||
|
dbObject.put(part, nestedDbObject);
|
||||||
|
dbObject = nestedDbObject;
|
||||||
|
} else {
|
||||||
|
dbObject.put(part, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value the given {@link MongoPersistentProperty} refers to. By default this will be a direct field but
|
||||||
|
* the method will also transparently resolve nested values the {@link MongoPersistentProperty} might refer to through
|
||||||
|
* a path expression in the field name metadata.
|
||||||
|
*
|
||||||
|
* @param property must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object get(MongoPersistentProperty property) {
|
||||||
|
|
||||||
|
String fieldName = property.getFieldName();
|
||||||
|
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||||
|
Map<Object, Object> source = this.dbObject.toMap();
|
||||||
|
Object result = null;
|
||||||
|
|
||||||
|
while (source != null && parts.hasNext()) {
|
||||||
|
|
||||||
|
result = source.get(parts.next());
|
||||||
|
|
||||||
|
if (parts.hasNext()) {
|
||||||
|
source = getAsMap(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<Object, Object> getAsMap(Object source) {
|
||||||
|
|
||||||
|
if (source instanceof BasicDBObject) {
|
||||||
|
return ((DBObject) source).toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source instanceof Map) {
|
||||||
|
return (Map<Object, Object>) source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 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.
|
||||||
@@ -31,18 +31,30 @@ import com.mongodb.DBObject;
|
|||||||
*/
|
*/
|
||||||
class DBObjectPropertyAccessor extends MapAccessor {
|
class DBObjectPropertyAccessor extends MapAccessor {
|
||||||
|
|
||||||
static MapAccessor INSTANCE = new DBObjectPropertyAccessor();
|
static final MapAccessor INSTANCE = new DBObjectPropertyAccessor();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.context.expression.MapAccessor#getSpecificTargetClasses()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<?>[] getSpecificTargetClasses() {
|
public Class<?>[] getSpecificTargetClasses() {
|
||||||
return new Class[] { DBObject.class };
|
return new Class[] { DBObject.class };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.context.expression.MapAccessor#canRead(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean canRead(EvaluationContext context, Object target, String name) {
|
public boolean canRead(EvaluationContext context, Object target, String name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.context.expression.MapAccessor#read(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public TypedValue read(EvaluationContext context, Object target, String name) {
|
public TypedValue read(EvaluationContext context, Object target, String name) {
|
||||||
@@ -52,4 +64,4 @@ class DBObjectPropertyAccessor extends MapAccessor {
|
|||||||
Object value = source.get(name);
|
Object value = source.get(name);
|
||||||
return value == null ? TypedValue.NULL : new TypedValue(value);
|
return value == null ? TypedValue.NULL : new TypedValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to resolve associations annotated with {@link org.springframework.data.mongodb.core.mapping.DBRef}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public interface DbRefResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the given {@link DBRef} into an object of the given {@link MongoPersistentProperty}'s type. The method
|
||||||
|
* might return a proxy object for the {@link DBRef} or resolve it immediately. In both cases the
|
||||||
|
* {@link DbRefResolverCallback} will be used to obtain the actual backing object.
|
||||||
|
*
|
||||||
|
* @param property will never be {@literal null}.
|
||||||
|
* @param dbref the {@link DBRef} to resolve.
|
||||||
|
* @param callback will never be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link DBRef} instance for the given {@link org.springframework.data.mongodb.core.mapping.DBRef}
|
||||||
|
* annotation, {@link MongoPersistentEntity} and id.
|
||||||
|
*
|
||||||
|
* @param annotation will never be {@literal null}.
|
||||||
|
* @param entity will never be {@literal null}.
|
||||||
|
* @param id will never be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity<?> entity,
|
||||||
|
Object id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface to be used in conjunction with {@link DbRefResolver}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public interface DbRefResolverCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the final object for the given {@link MongoPersistentProperty}.
|
||||||
|
*
|
||||||
|
* @param property will never be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object resolve(MongoPersistentProperty property);
|
||||||
|
}
|
||||||
@@ -0,0 +1,398 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert;
|
||||||
|
|
||||||
|
import static org.springframework.util.ReflectionUtils.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.objenesis.Objenesis;
|
||||||
|
import org.objenesis.ObjenesisStd;
|
||||||
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.cglib.proxy.Callback;
|
||||||
|
import org.springframework.cglib.proxy.Enhancer;
|
||||||
|
import org.springframework.cglib.proxy.Factory;
|
||||||
|
import org.springframework.cglib.proxy.MethodProxy;
|
||||||
|
import org.springframework.core.SpringVersion;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
|
import org.springframework.data.mongodb.LazyLoadingException;
|
||||||
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DbRefResolver} that resolves {@link org.springframework.data.mongodb.core.mapping.DBRef}s by delegating to a
|
||||||
|
* {@link DbRefResolverCallback} than is able to generate lazy loading proxies.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
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 PersistenceExceptionTranslator exceptionTranslator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}.
|
||||||
|
*
|
||||||
|
* @param mongoDbFactory must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public DefaultDbRefResolver(MongoDbFactory mongoDbFactory) {
|
||||||
|
|
||||||
|
Assert.notNull(mongoDbFactory, "MongoDbFactory translator must not be null!");
|
||||||
|
|
||||||
|
this.mongoDbFactory = mongoDbFactory;
|
||||||
|
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||||
|
|
||||||
|
Assert.notNull(property, "Property must not be null!");
|
||||||
|
Assert.notNull(callback, "Callback must not be null!");
|
||||||
|
|
||||||
|
if (isLazyDbRef(property)) {
|
||||||
|
return createLazyLoadingProxy(property, dbref, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback.resolve(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#created(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
|
||||||
|
MongoPersistentEntity<?> entity, Object id) {
|
||||||
|
|
||||||
|
DB db = mongoDbFactory.getDb();
|
||||||
|
db = annotation != null && StringUtils.hasText(annotation.db()) ? mongoDbFactory.getDb(annotation.db()) : db;
|
||||||
|
|
||||||
|
return new DBRef(db, entity.getCollection(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a proxy for the given {@link MongoPersistentProperty} using the given {@link DbRefResolverCallback} to
|
||||||
|
* eventually resolve the value of the property.
|
||||||
|
*
|
||||||
|
* @param property must not be {@literal null}.
|
||||||
|
* @param dbref can be {@literal null}.
|
||||||
|
* @param callback must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||||
|
|
||||||
|
ProxyFactory proxyFactory = new ProxyFactory();
|
||||||
|
Class<?> propertyType = property.getType();
|
||||||
|
|
||||||
|
for (Class<?> type : propertyType.getInterfaces()) {
|
||||||
|
proxyFactory.addInterface(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||||
|
|
||||||
|
proxyFactory.addInterface(LazyLoadingProxy.class);
|
||||||
|
|
||||||
|
if (propertyType.isInterface()) {
|
||||||
|
proxyFactory.addInterface(propertyType);
|
||||||
|
proxyFactory.addAdvice(interceptor);
|
||||||
|
return proxyFactory.getProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyFactory.setProxyTargetClass(true);
|
||||||
|
proxyFactory.setTargetClass(propertyType);
|
||||||
|
|
||||||
|
if (IS_SPRING_4_OR_BETTER || !OBJENESIS_PRESENT) {
|
||||||
|
proxyFactory.addAdvice(interceptor);
|
||||||
|
return proxyFactory.getProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjenesisProxyEnhancer.enhanceAndGet(proxyFactory, propertyType, interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the property shall be resolved lazily.
|
||||||
|
*
|
||||||
|
* @param property must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isLazyDbRef(MongoPersistentProperty property) {
|
||||||
|
return property.getDBRef() != null && property.getDBRef().lazy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link MethodInterceptor} that is used within a lazy loading proxy. The property resolving is delegated to a
|
||||||
|
* {@link DbRefResolverCallback}. The resolving process is triggered by a method invocation on the proxy and is
|
||||||
|
* guaranteed to be performed only once.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
||||||
|
Serializable {
|
||||||
|
|
||||||
|
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD;
|
||||||
|
|
||||||
|
private final DbRefResolverCallback callback;
|
||||||
|
private final MongoPersistentProperty property;
|
||||||
|
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||||
|
|
||||||
|
private volatile boolean resolved;
|
||||||
|
private Object result;
|
||||||
|
private DBRef dbref;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("initialize");
|
||||||
|
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link LazyLoadingInterceptor} for the given {@link MongoPersistentProperty},
|
||||||
|
* {@link PersistenceExceptionTranslator} and {@link DbRefResolverCallback}.
|
||||||
|
*
|
||||||
|
* @param property must not be {@literal null}.
|
||||||
|
* @param dbref can be {@literal null}.
|
||||||
|
* @param callback must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public LazyLoadingInterceptor(MongoPersistentProperty property, DBRef dbref,
|
||||||
|
PersistenceExceptionTranslator exceptionTranslator, DbRefResolverCallback callback) {
|
||||||
|
|
||||||
|
Assert.notNull(property, "Property must not be null!");
|
||||||
|
Assert.notNull(exceptionTranslator, "Exception translator must not be null!");
|
||||||
|
Assert.notNull(callback, "Callback must not be null!");
|
||||||
|
|
||||||
|
this.dbref = dbref;
|
||||||
|
this.callback = callback;
|
||||||
|
this.exceptionTranslator = exceptionTranslator;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||||
|
return intercept(invocation.getThis(), invocation.getMethod(), invocation.getArguments(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], org.springframework.cglib.proxy.MethodProxy)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||||
|
|
||||||
|
if (INITIALIZE_METHOD.equals(method)) {
|
||||||
|
return ensureResolved();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TO_DBREF_METHOD.equals(method)) {
|
||||||
|
return this.dbref;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isObjectMethod(method) && Object.class.equals(method.getDeclaringClass())) {
|
||||||
|
|
||||||
|
if (ReflectionUtils.isToStringMethod(method)) {
|
||||||
|
return proxyToString(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReflectionUtils.isEqualsMethod(method)) {
|
||||||
|
return proxyEquals(proxy, args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||||
|
return proxyHashCode(proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object target = ensureResolved();
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return method.invoke(target, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a to string representation for the given {@code proxy}.
|
||||||
|
*
|
||||||
|
* @param proxy
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String proxyToString(Object proxy) {
|
||||||
|
|
||||||
|
StringBuilder description = new StringBuilder();
|
||||||
|
if (dbref != null) {
|
||||||
|
description.append(dbref.getRef());
|
||||||
|
description.append(":");
|
||||||
|
description.append(dbref.getId());
|
||||||
|
} else {
|
||||||
|
description.append(System.identityHashCode(proxy));
|
||||||
|
}
|
||||||
|
description.append("$").append(LazyLoadingProxy.class.getSimpleName());
|
||||||
|
|
||||||
|
return description.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hashcode for the given {@code proxy}.
|
||||||
|
*
|
||||||
|
* @param proxy
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int proxyHashCode(Object proxy) {
|
||||||
|
return proxyToString(proxy).hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an equality check for the given {@code proxy}.
|
||||||
|
*
|
||||||
|
* @param proxy
|
||||||
|
* @param that
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean proxyEquals(Object proxy, Object that) {
|
||||||
|
|
||||||
|
if (!(that instanceof LazyLoadingProxy)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (that == proxy) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxyToString(proxy).equals(that.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will trigger the resolution if the proxy is not resolved already or return a previously resolved result.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Object ensureResolved() {
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
this.result = resolve();
|
||||||
|
this.resolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method for serialization.
|
||||||
|
*
|
||||||
|
* @param out
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
|
||||||
|
ensureResolved();
|
||||||
|
out.writeObject(this.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method for deserialization.
|
||||||
|
*
|
||||||
|
* @param in
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void readObject(ObjectInputStream in) throws IOException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.resolved = true;
|
||||||
|
this.result = in.readObject();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new LazyLoadingException("Could not deserialize result", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the proxy into its backing object.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private synchronized Object resolve() {
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
return callback.resolve(property);
|
||||||
|
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
|
||||||
|
DataAccessException translatedException = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||||
|
throw new LazyLoadingException("Unable to lazily resolve DBRef!", translatedException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,520 @@
|
|||||||
|
/*
|
||||||
|
* 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.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.data.convert.ReadingConverter;
|
||||||
|
import org.springframework.data.convert.WritingConverter;
|
||||||
|
import org.springframework.data.geo.Box;
|
||||||
|
import org.springframework.data.geo.Circle;
|
||||||
|
import org.springframework.data.geo.Distance;
|
||||||
|
import org.springframework.data.geo.Metrics;
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.geo.Polygon;
|
||||||
|
import org.springframework.data.geo.Shape;
|
||||||
|
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||||
|
import org.springframework.data.mongodb.core.query.GeoCommand;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class to contain useful geo structure converters for the usage with Mongo.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
abstract class GeoConverters {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation.
|
||||||
|
*/
|
||||||
|
private GeoConverters() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the geo converters to be registered.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Collection<? extends Object> getConvertersToRegister() {
|
||||||
|
return Arrays.asList( //
|
||||||
|
BoxToDbObjectConverter.INSTANCE //
|
||||||
|
, PolygonToDbObjectConverter.INSTANCE //
|
||||||
|
, CircleToDbObjectConverter.INSTANCE //
|
||||||
|
, LegacyCircleToDbObjectConverter.INSTANCE //
|
||||||
|
, SphereToDbObjectConverter.INSTANCE //
|
||||||
|
, DbObjectToBoxConverter.INSTANCE //
|
||||||
|
, DbObjectToPolygonConverter.INSTANCE //
|
||||||
|
, DbObjectToCircleConverter.INSTANCE //
|
||||||
|
, DbObjectToLegacyCircleConverter.INSTANCE //
|
||||||
|
, DbObjectToSphereConverter.INSTANCE //
|
||||||
|
, DbObjectToPointConverter.INSTANCE //
|
||||||
|
, PointToDbObjectConverter.INSTANCE //
|
||||||
|
, GeoCommandToDbObjectConverter.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link List} of {@link Double}s into a {@link Point}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public Point convert(DBObject source) {
|
||||||
|
|
||||||
|
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"),
|
||||||
|
(Double) source.get("y"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Point} into a {@link List} of {@link Double}s.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(Point source) {
|
||||||
|
return source == null ? null : new BasicDBObject("x", source.getX()).append("y", source.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Box} into a {@link BasicDBList}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@WritingConverter
|
||||||
|
public static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(Box source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicDBObject result = new BasicDBObject();
|
||||||
|
result.put("first", PointToDbObjectConverter.INSTANCE.convert(source.getFirst()));
|
||||||
|
result.put("second", PointToDbObjectConverter.INSTANCE.convert(source.getSecond()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Box}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public Box convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point first = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("first"));
|
||||||
|
Point second = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("second"));
|
||||||
|
|
||||||
|
return new org.springframework.data.mongodb.core.geo.Box(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Circle} into a {@link BasicDBList}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(Circle source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject result = new BasicDBObject();
|
||||||
|
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
|
||||||
|
result.put("radius", source.getRadius().getNormalizedValue());
|
||||||
|
result.put("metric", source.getRadius().getMetric().toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link DBObject} into a {@link org.springframework.data.mongodb.core.geo.Circle}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Circle convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject center = (DBObject) source.get("center");
|
||||||
|
Double radius = (Double) source.get("radius");
|
||||||
|
|
||||||
|
Distance distance = new Distance(radius);
|
||||||
|
|
||||||
|
if (source.containsField("metric")) {
|
||||||
|
|
||||||
|
String metricString = (String) source.get("metric");
|
||||||
|
Assert.notNull(metricString, "Metric must not be null!");
|
||||||
|
|
||||||
|
distance = distance.in(Metrics.valueOf(metricString));
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.notNull(center, "Center must not be null!");
|
||||||
|
Assert.notNull(radius, "Radius must not be null!");
|
||||||
|
|
||||||
|
return new Circle(DbObjectToPointConverter.INSTANCE.convert(center), distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(Sphere source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject result = new BasicDBObject();
|
||||||
|
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
|
||||||
|
result.put("radius", source.getRadius().getNormalizedValue());
|
||||||
|
result.put("metric", source.getRadius().getMetric().toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link BasicDBList} into a {@link Sphere}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Sphere convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject center = (DBObject) source.get("center");
|
||||||
|
Double radius = (Double) source.get("radius");
|
||||||
|
|
||||||
|
Distance distance = new Distance(radius);
|
||||||
|
|
||||||
|
if (source.containsField("metric")) {
|
||||||
|
|
||||||
|
String metricString = (String) source.get("metric");
|
||||||
|
Assert.notNull(metricString, "Metric must not be null!");
|
||||||
|
|
||||||
|
distance = distance.in(Metrics.valueOf(metricString));
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.notNull(center, "Center must not be null!");
|
||||||
|
Assert.notNull(radius, "Radius must not be null!");
|
||||||
|
|
||||||
|
return new Sphere(DbObjectToPointConverter.INSTANCE.convert(center), distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Polygon} into a {@link BasicDBList}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DBObject convert(Polygon source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Point> points = source.getPoints();
|
||||||
|
List<DBObject> pointTuples = new ArrayList<DBObject>(points.size());
|
||||||
|
|
||||||
|
for (Point point : points) {
|
||||||
|
pointTuples.add(PointToDbObjectConverter.INSTANCE.convert(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject result = new BasicDBObject();
|
||||||
|
result.put("points", pointTuples);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Polygon}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||||
|
public Polygon convert(DBObject source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DBObject> points = (List<DBObject>) source.get("points");
|
||||||
|
List<Point> newPoints = new ArrayList<Point>(points.size());
|
||||||
|
|
||||||
|
for (DBObject element : points) {
|
||||||
|
|
||||||
|
Assert.notNull(element, "Point elements of polygon must not be null!");
|
||||||
|
newPoints.add(DbObjectToPointConverter.INSTANCE.convert(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new org.springframework.data.mongodb.core.geo.Polygon(newPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Sphere} into a {@link BasicDBList}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public DBObject convert(GeoCommand source) {
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicDBList argument = new BasicDBList();
|
||||||
|
|
||||||
|
Shape shape = source.getShape();
|
||||||
|
|
||||||
|
if (shape instanceof Box) {
|
||||||
|
|
||||||
|
argument.add(toList(((Box) shape).getFirst()));
|
||||||
|
argument.add(toList(((Box) shape).getSecond()));
|
||||||
|
|
||||||
|
} else if (shape instanceof Circle) {
|
||||||
|
|
||||||
|
argument.add(toList(((Circle) shape).getCenter()));
|
||||||
|
argument.add(((Circle) shape).getRadius().getNormalizedValue());
|
||||||
|
|
||||||
|
} else if (shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
|
||||||
|
|
||||||
|
argument.add(toList(((org.springframework.data.mongodb.core.geo.Circle) shape).getCenter()));
|
||||||
|
argument.add(((org.springframework.data.mongodb.core.geo.Circle) shape).getRadius());
|
||||||
|
|
||||||
|
} else if (shape instanceof Polygon) {
|
||||||
|
|
||||||
|
for (Point point : ((Polygon) shape).getPoints()) {
|
||||||
|
argument.add(toList(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (shape instanceof Sphere) {
|
||||||
|
|
||||||
|
argument.add(toList(((Sphere) shape).getCenter()));
|
||||||
|
argument.add(((Sphere) shape).getRadius().getNormalizedValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BasicDBObject(source.getCommand(), argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Double> toList(Point point) {
|
||||||
|
return Arrays.asList(point.getX(), point.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
|
||||||
|
|
||||||
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows direct interaction with the underlying {@link LazyLoadingInterceptor}.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public interface LazyLoadingProxy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the proxy and returns the wrapped value.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
Object initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link DBRef} represented by this {@link LazyLoadingProxy}, may be null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
DBRef toDBRef();
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 by the original author(s).
|
* Copyright 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.
|
||||||
@@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.core.CollectionFactory;
|
|
||||||
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.ConversionServiceFactory;
|
||||||
|
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;
|
||||||
@@ -57,11 +57,9 @@ 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.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
import com.mongodb.BasicDBList;
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DB;
|
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
import com.mongodb.DBRef;
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
@@ -73,38 +71,38 @@ import com.mongodb.DBRef;
|
|||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Patrik Wasik
|
* @author Patrik Wasik
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||||
|
|
||||||
protected static final Logger log = LoggerFactory.getLogger(MappingMongoConverter.class);
|
protected static final Logger LOGGER = LoggerFactory.getLogger(MappingMongoConverter.class);
|
||||||
|
|
||||||
protected final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
protected final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||||
protected final MongoDbFactory mongoDbFactory;
|
|
||||||
protected final QueryMapper idMapper;
|
protected final QueryMapper idMapper;
|
||||||
|
protected final DbRefResolver dbRefResolver;
|
||||||
protected ApplicationContext applicationContext;
|
protected ApplicationContext applicationContext;
|
||||||
protected boolean useFieldAccessOnly = true;
|
|
||||||
protected MongoTypeMapper typeMapper;
|
protected MongoTypeMapper typeMapper;
|
||||||
protected String mapKeyDotReplacement = null;
|
protected String mapKeyDotReplacement = null;
|
||||||
|
|
||||||
private SpELContext spELContext;
|
private SpELContext spELContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link MappingMongoConverter} given the new {@link MongoDbFactory} and {@link MappingContext}.
|
* Creates a new {@link MappingMongoConverter} given the new {@link DbRefResolver} and {@link MappingContext}.
|
||||||
*
|
*
|
||||||
* @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")
|
@SuppressWarnings("deprecation")
|
||||||
public MappingMongoConverter(MongoDbFactory mongoDbFactory,
|
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
||||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
|
||||||
super(ConversionServiceFactory.createDefaultConversionService());
|
super(ConversionServiceFactory.createDefaultConversionService());
|
||||||
|
|
||||||
Assert.notNull(mongoDbFactory);
|
Assert.notNull(dbRefResolver, "DbRefResolver must not be null!");
|
||||||
Assert.notNull(mappingContext);
|
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||||
|
|
||||||
this.mongoDbFactory = mongoDbFactory;
|
this.dbRefResolver = dbRefResolver;
|
||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext);
|
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext);
|
||||||
this.idMapper = new QueryMapper(this);
|
this.idMapper = new QueryMapper(this);
|
||||||
@@ -112,6 +110,19 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
this.spELContext = new SpELContext(DBObjectPropertyAccessor.INSTANCE);
|
this.spELContext = new SpELContext(DBObjectPropertyAccessor.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link MappingMongoConverter} given the new {@link MongoDbFactory} and {@link MappingContext}.
|
||||||
|
*
|
||||||
|
* @deprecated use the constructor taking a {@link DbRefResolver} instead.
|
||||||
|
* @param mongoDbFactory must not be {@literal null}.
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public MappingMongoConverter(MongoDbFactory mongoDbFactory,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
this(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the {@link MongoTypeMapper} to be used to add type information to {@link DBObject}s created by the
|
* Configures the {@link MongoTypeMapper} to be used to add type information to {@link DBObject}s created by the
|
||||||
* converter and how to lookup type information from {@link DBObject}s when reading them. Uses a
|
* converter and how to lookup type information from {@link DBObject}s when reading them. Uses a
|
||||||
@@ -154,17 +165,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return mappingContext;
|
return mappingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures whether to use field access only for entity mapping. Setting this to true will force the
|
|
||||||
* {@link MongoConverter} to not go through getters or setters even if they are present for getting and setting
|
|
||||||
* property values.
|
|
||||||
*
|
|
||||||
* @param useFieldAccessOnly
|
|
||||||
*/
|
|
||||||
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
|
|
||||||
this.useFieldAccessOnly = useFieldAccessOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||||
@@ -234,7 +234,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
parent);
|
parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, Object parent) {
|
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final Object parent) {
|
||||||
|
|
||||||
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(dbo, spELContext);
|
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(dbo, spELContext);
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||||
S instance = instantiator.createInstance(entity, provider);
|
S instance = instantiator.createInstance(entity, provider);
|
||||||
|
|
||||||
final BeanWrapper<MongoPersistentEntity<S>, S> wrapper = BeanWrapper.create(instance, conversionService);
|
final BeanWrapper<S> wrapper = BeanWrapper.create(instance, conversionService);
|
||||||
final S result = wrapper.getBean();
|
final S result = wrapper.getBean();
|
||||||
|
|
||||||
// Set properties not already set in the constructor
|
// Set properties not already set in the constructor
|
||||||
@@ -254,18 +254,27 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object obj = getValueInternal(prop, dbo, evaluator, result);
|
Object obj = getValueInternal(prop, dbo, evaluator, result);
|
||||||
wrapper.setProperty(prop, obj, useFieldAccessOnly);
|
wrapper.setProperty(prop, obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle associations
|
// Handle associations
|
||||||
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();
|
|
||||||
Object obj = getValueInternal(inverseProp, dbo, evaluator, result);
|
|
||||||
|
|
||||||
wrapper.setProperty(inverseProp, obj);
|
MongoPersistentProperty property = association.getInverse();
|
||||||
|
|
||||||
|
Object value = dbo.get(property.getName());
|
||||||
|
DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
|
||||||
|
Object obj = dbRefResolver.resolveDbRef(property, dbref, new DbRefResolverCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolve(MongoPersistentProperty property) {
|
||||||
|
return getValueInternal(property, dbo, evaluator, parent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.setProperty(property, obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -285,7 +294,7 @@ 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return createDBRef(object, annotation);
|
return createDBRef(object, referingProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -356,15 +365,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<MongoPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(obj, conversionService);
|
final BeanWrapper<Object> wrapper = BeanWrapper.create(obj, conversionService);
|
||||||
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||||
|
|
||||||
if (!dbo.containsField("_id") && null != idProperty) {
|
if (!dbo.containsField("_id") && null != idProperty) {
|
||||||
|
|
||||||
boolean fieldAccessOnly = idProperty.usePropertyAccess() ? false : useFieldAccessOnly;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object id = wrapper.getProperty(idProperty, Object.class, fieldAccessOnly);
|
Object id = wrapper.getProperty(idProperty, Object.class);
|
||||||
dbo.put("_id", idMapper.convertId(id));
|
dbo.put("_id", idMapper.convertId(id));
|
||||||
} catch (ConversionException ignored) {}
|
} catch (ConversionException ignored) {}
|
||||||
}
|
}
|
||||||
@@ -377,15 +384,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean fieldAccessOnly = prop.usePropertyAccess() ? false : useFieldAccessOnly;
|
Object propertyObj = wrapper.getProperty(prop);
|
||||||
|
|
||||||
Object propertyObj = wrapper.getProperty(prop, prop.getType(), fieldAccessOnly);
|
|
||||||
|
|
||||||
if (null != propertyObj) {
|
if (null != propertyObj) {
|
||||||
|
|
||||||
if (!conversions.isSimpleType(propertyObj.getClass())) {
|
if (!conversions.isSimpleType(propertyObj.getClass())) {
|
||||||
writePropertyInternal(propertyObj, dbo, prop);
|
writePropertyInternal(propertyObj, dbo, prop);
|
||||||
} else {
|
} else {
|
||||||
writeSimpleInternal(propertyObj, dbo, prop.getFieldName());
|
writeSimpleInternal(propertyObj, dbo, prop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +401,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||||
MongoPersistentProperty inverseProp = association.getInverse();
|
MongoPersistentProperty inverseProp = association.getInverse();
|
||||||
Class<?> type = inverseProp.getType();
|
Class<?> type = inverseProp.getType();
|
||||||
Object propertyObj = wrapper.getProperty(inverseProp, type, useFieldAccessOnly);
|
Object propertyObj = wrapper.getProperty(inverseProp, type);
|
||||||
if (null != propertyObj) {
|
if (null != propertyObj) {
|
||||||
writePropertyInternal(propertyObj, dbo, inverseProp);
|
writePropertyInternal(propertyObj, dbo, inverseProp);
|
||||||
}
|
}
|
||||||
@@ -410,46 +416,68 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = prop.getFieldName();
|
DBObjectAccessor accessor = new DBObjectAccessor(dbo);
|
||||||
|
|
||||||
TypeInformation<?> valueType = ClassTypeInformation.from(obj.getClass());
|
TypeInformation<?> valueType = ClassTypeInformation.from(obj.getClass());
|
||||||
TypeInformation<?> type = prop.getTypeInformation();
|
TypeInformation<?> type = prop.getTypeInformation();
|
||||||
|
|
||||||
if (valueType.isCollectionLike()) {
|
if (valueType.isCollectionLike()) {
|
||||||
DBObject collectionInternal = createCollection(asCollection(obj), prop);
|
DBObject collectionInternal = createCollection(asCollection(obj), prop);
|
||||||
dbo.put(name, collectionInternal);
|
accessor.put(prop, collectionInternal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueType.isMap()) {
|
if (valueType.isMap()) {
|
||||||
DBObject mapDbObj = createMap((Map<Object, Object>) obj, prop);
|
DBObject mapDbObj = createMap((Map<Object, Object>) obj, prop);
|
||||||
dbo.put(name, mapDbObj);
|
accessor.put(prop, mapDbObj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prop.isDbReference()) {
|
if (prop.isDbReference()) {
|
||||||
DBRef dbRefObj = createDBRef(obj, prop.getDBRef());
|
|
||||||
|
DBRef dbRefObj = null;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we already have a LazyLoadingProxy, we use it's cached DBRef value instead of
|
||||||
|
* unnecessarily initializing it only to convert it to a DBRef a few instructions later.
|
||||||
|
*/
|
||||||
|
if (obj instanceof LazyLoadingProxy) {
|
||||||
|
dbRefObj = ((LazyLoadingProxy) obj).toDBRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
dbRefObj = dbRefObj != null ? dbRefObj : createDBRef(obj, prop);
|
||||||
|
|
||||||
if (null != dbRefObj) {
|
if (null != dbRefObj) {
|
||||||
dbo.put(name, dbRefObj);
|
accessor.put(prop, dbRefObj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a LazyLoadingProxy we make sure it is initialized first.
|
||||||
|
*/
|
||||||
|
if (obj instanceof LazyLoadingProxy) {
|
||||||
|
obj = ((LazyLoadingProxy) obj).initialize();
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup potential custom target type
|
// Lookup potential custom target type
|
||||||
Class<?> basicTargetType = conversions.getCustomWriteTarget(obj.getClass(), null);
|
Class<?> basicTargetType = conversions.getCustomWriteTarget(obj.getClass(), null);
|
||||||
|
|
||||||
if (basicTargetType != null) {
|
if (basicTargetType != null) {
|
||||||
dbo.put(name, conversionService.convert(obj, basicTargetType));
|
accessor.put(prop, conversionService.convert(obj, basicTargetType));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicDBObject propDbObj = new BasicDBObject();
|
Object existingValue = accessor.get(prop);
|
||||||
|
BasicDBObject propDbObj = existingValue instanceof BasicDBObject ? (BasicDBObject) existingValue
|
||||||
|
: new BasicDBObject();
|
||||||
addCustomTypeKeyIfNecessary(type, obj, propDbObj);
|
addCustomTypeKeyIfNecessary(type, 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);
|
||||||
|
|
||||||
writeInternal(obj, propDbObj, entity);
|
writeInternal(obj, propDbObj, entity);
|
||||||
dbo.put(name, propDbObj);
|
accessor.put(prop, propDbObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSubtype(Class<?> left, Class<?> right) {
|
private boolean isSubtype(Class<?> left, Class<?> right) {
|
||||||
@@ -494,7 +522,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBRef dbRef = createDBRef(element, property.getDBRef());
|
DBRef dbRef = createDBRef(element, property);
|
||||||
dbList.add(dbRef);
|
dbList.add(dbRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +555,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 = potentiallyEscapeMapKey(key.toString());
|
||||||
dbObject.put(simpleKey, value != null ? createDBRef(value, property.getDBRef()) : null);
|
dbObject.put(simpleKey, value != null ? createDBRef(value, property) : null);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new MappingException("Cannot use a complex object as a key value.");
|
throw new MappingException("Cannot use a complex object as a key value.");
|
||||||
@@ -647,7 +675,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
*/
|
*/
|
||||||
protected void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
|
protected void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
|
||||||
|
|
||||||
TypeInformation<?> actualType = type != null ? type.getActualType() : type;
|
TypeInformation<?> actualType = type != null ? type.getActualType() : null;
|
||||||
Class<?> reference = actualType == null ? Object.class : actualType.getType();
|
Class<?> reference = actualType == null ? Object.class : actualType.getType();
|
||||||
|
|
||||||
boolean notTheSameClass = !value.getClass().equals(reference);
|
boolean notTheSameClass = !value.getClass().equals(reference);
|
||||||
@@ -667,6 +695,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
dbObject.put(key, getPotentiallyConvertedSimpleWrite(value));
|
dbObject.put(key, getPotentiallyConvertedSimpleWrite(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeSimpleInternal(Object value, DBObject dbObject, MongoPersistentProperty property) {
|
||||||
|
DBObjectAccessor accessor = new DBObjectAccessor(dbObject);
|
||||||
|
accessor.put(property, getPotentiallyConvertedSimpleWrite(value));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Mongo type.
|
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Mongo type.
|
||||||
* Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
|
* Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
|
||||||
@@ -715,7 +748,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return target.isAssignableFrom(value.getClass()) ? value : conversionService.convert(value, target);
|
return target.isAssignableFrom(value.getClass()) ? value : conversionService.convert(value, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DBRef createDBRef(Object target, org.springframework.data.mongodb.core.mapping.DBRef dbref) {
|
protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
|
||||||
|
|
||||||
Assert.notNull(target);
|
Assert.notNull(target);
|
||||||
|
|
||||||
@@ -724,6 +757,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
}
|
}
|
||||||
|
|
||||||
MongoPersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
|
MongoPersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
|
||||||
|
targetEntity = targetEntity == null ? targetEntity = mappingContext.getPersistentEntity(property) : targetEntity;
|
||||||
|
|
||||||
if (null == targetEntity) {
|
if (null == targetEntity) {
|
||||||
throw new MappingException("No mapping metadata found for " + target.getClass());
|
throw new MappingException("No mapping metadata found for " + target.getClass());
|
||||||
@@ -735,17 +769,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
throw new MappingException("No id property found on class " + targetEntity.getType());
|
throw new MappingException("No id property found on class " + targetEntity.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanWrapper<MongoPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(target, conversionService);
|
Object id = null;
|
||||||
Object id = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);
|
|
||||||
|
if (target.getClass().equals(idProperty.getType())) {
|
||||||
|
id = target;
|
||||||
|
} else {
|
||||||
|
BeanWrapper<Object> wrapper = BeanWrapper.create(target, conversionService);
|
||||||
|
id = wrapper.getProperty(idProperty, Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
if (null == id) {
|
if (null == id) {
|
||||||
throw new MappingException("Cannot create a reference to an object with a NULL id.");
|
throw new MappingException("Cannot create a reference to an object with a NULL id.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DB db = mongoDbFactory.getDb();
|
return dbRefResolver.createDbRef(property == null ? null : property.getDBRef(), targetEntity,
|
||||||
db = dbref != null && StringUtils.hasText(dbref.db()) ? mongoDbFactory.getDb(dbref.db()) : db;
|
idMapper.convertId(id));
|
||||||
|
|
||||||
return new DBRef(db, targetEntity.getCollection(), idMapper.convertId(id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator eval,
|
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator eval,
|
||||||
@@ -762,7 +800,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
* @param sourceValue must not be {@literal null}.
|
* @param sourceValue 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}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, Object parent) {
|
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, Object parent) {
|
||||||
|
|
||||||
Assert.notNull(targetType);
|
Assert.notNull(targetType);
|
||||||
@@ -773,19 +810,19 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return getPotentiallyConvertedSimpleRead(new HashSet<Object>(), collectionType);
|
return getPotentiallyConvertedSimpleRead(new HashSet<Object>(), collectionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
|
||||||
|
|
||||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory
|
|
||||||
.createCollection(collectionType, sourceValue.size());
|
|
||||||
TypeInformation<?> componentType = targetType.getComponentType();
|
TypeInformation<?> componentType = targetType.getComponentType();
|
||||||
Class<?> rawComponentType = componentType == null ? null : componentType.getType();
|
Class<?> rawComponentType = componentType == null ? null : componentType.getType();
|
||||||
|
|
||||||
|
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
||||||
|
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory
|
||||||
|
.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||||
|
|
||||||
for (int i = 0; i < sourceValue.size(); i++) {
|
for (int i = 0; i < sourceValue.size(); i++) {
|
||||||
|
|
||||||
Object dbObjItem = sourceValue.get(i);
|
Object dbObjItem = sourceValue.get(i);
|
||||||
|
|
||||||
if (dbObjItem instanceof DBRef) {
|
if (dbObjItem instanceof DBRef) {
|
||||||
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, ((DBRef) dbObjItem).fetch(),
|
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem),
|
||||||
parent));
|
parent));
|
||||||
} else if (dbObjItem instanceof DBObject) {
|
} else if (dbObjItem instanceof DBObject) {
|
||||||
items.add(read(componentType, (DBObject) dbObjItem, parent));
|
items.add(read(componentType, (DBObject) dbObjItem, parent));
|
||||||
@@ -810,7 +847,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
Assert.notNull(dbObject);
|
Assert.notNull(dbObject);
|
||||||
|
|
||||||
Class<?> mapType = typeMapper.readType(dbObject, type).getType();
|
Class<?> mapType = typeMapper.readType(dbObject, type).getType();
|
||||||
Map<Object, Object> map = CollectionFactory.createMap(mapType, dbObject.keySet().size());
|
|
||||||
|
TypeInformation<?> keyType = type.getComponentType();
|
||||||
|
Class<?> rawKeyType = keyType == null ? null : keyType.getType();
|
||||||
|
|
||||||
|
TypeInformation<?> valueType = type.getMapValueType();
|
||||||
|
Class<?> rawValueType = valueType == null ? null : valueType.getType();
|
||||||
|
|
||||||
|
Map<Object, Object> map = CollectionFactory.createMap(mapType, rawKeyType, dbObject.keySet().size());
|
||||||
Map<String, Object> sourceMap = dbObject.toMap();
|
Map<String, Object> sourceMap = dbObject.toMap();
|
||||||
|
|
||||||
for (Entry<String, Object> entry : sourceMap.entrySet()) {
|
for (Entry<String, Object> entry : sourceMap.entrySet()) {
|
||||||
@@ -820,20 +864,16 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
|
|
||||||
Object key = potentiallyUnescapeMapKey(entry.getKey());
|
Object key = potentiallyUnescapeMapKey(entry.getKey());
|
||||||
|
|
||||||
TypeInformation<?> keyTypeInformation = type.getComponentType();
|
if (rawKeyType != null) {
|
||||||
if (keyTypeInformation != null) {
|
key = conversionService.convert(key, rawKeyType);
|
||||||
Class<?> keyType = keyTypeInformation.getType();
|
|
||||||
key = conversionService.convert(key, keyType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object value = entry.getValue();
|
Object value = entry.getValue();
|
||||||
TypeInformation<?> valueType = type.getMapValueType();
|
|
||||||
Class<?> rawValueType = valueType == null ? null : valueType.getType();
|
|
||||||
|
|
||||||
if (value instanceof DBObject) {
|
if (value instanceof DBObject) {
|
||||||
map.put(key, read(valueType, (DBObject) value, parent));
|
map.put(key, read(valueType, (DBObject) value, parent));
|
||||||
} else if (value instanceof DBRef) {
|
} else if (value instanceof DBRef) {
|
||||||
map.put(key, DBRef.class.equals(rawValueType) ? value : read(valueType, ((DBRef) value).fetch()));
|
map.put(key, DBRef.class.equals(rawValueType) ? value : read(valueType, readRef((DBRef) value)));
|
||||||
} else {
|
} else {
|
||||||
Class<?> valueClass = valueType == null ? null : valueType.getType();
|
Class<?> valueClass = valueType == null ? null : valueType.getType();
|
||||||
map.put(key, getPotentiallyConvertedSimpleRead(value, valueClass));
|
map.put(key, getPotentiallyConvertedSimpleRead(value, valueClass));
|
||||||
@@ -879,15 +919,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return getPotentiallyConvertedSimpleWrite(obj);
|
return getPotentiallyConvertedSimpleWrite(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeInformation<?> typeHint = typeInformation == null ? null : ClassTypeInformation.OBJECT;
|
||||||
|
|
||||||
if (obj instanceof BasicDBList) {
|
if (obj instanceof BasicDBList) {
|
||||||
return maybeConvertList((BasicDBList) obj);
|
return maybeConvertList((BasicDBList) obj, typeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof DBObject) {
|
if (obj instanceof DBObject) {
|
||||||
DBObject newValueDbo = new BasicDBObject();
|
DBObject newValueDbo = new BasicDBObject();
|
||||||
for (String vk : ((DBObject) obj).keySet()) {
|
for (String vk : ((DBObject) obj).keySet()) {
|
||||||
Object o = ((DBObject) obj).get(vk);
|
Object o = ((DBObject) obj).get(vk);
|
||||||
newValueDbo.put(vk, convertToMongoType(o));
|
newValueDbo.put(vk, convertToMongoType(o, typeHint));
|
||||||
}
|
}
|
||||||
return newValueDbo;
|
return newValueDbo;
|
||||||
}
|
}
|
||||||
@@ -895,17 +937,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
if (obj instanceof Map) {
|
if (obj instanceof Map) {
|
||||||
DBObject result = new BasicDBObject();
|
DBObject result = new BasicDBObject();
|
||||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
|
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
|
||||||
result.put(entry.getKey().toString(), convertToMongoType(entry.getValue()));
|
result.put(entry.getKey().toString(), convertToMongoType(entry.getValue(), typeHint));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.getClass().isArray()) {
|
if (obj.getClass().isArray()) {
|
||||||
return maybeConvertList(Arrays.asList((Object[]) obj));
|
return maybeConvertList(Arrays.asList((Object[]) obj), typeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Collection) {
|
if (obj instanceof Collection) {
|
||||||
return maybeConvertList((Collection<?>) obj);
|
return maybeConvertList((Collection<?>) obj, typeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject newDbo = new BasicDBObject();
|
DBObject newDbo = new BasicDBObject();
|
||||||
@@ -918,11 +960,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo);
|
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicDBList maybeConvertList(Iterable<?> source) {
|
public BasicDBList maybeConvertList(Iterable<?> source, TypeInformation<?> typeInformation) {
|
||||||
|
|
||||||
BasicDBList newDbl = new BasicDBList();
|
BasicDBList newDbl = new BasicDBList();
|
||||||
for (Object element : source) {
|
for (Object element : source) {
|
||||||
newDbl.add(convertToMongoType(element));
|
newDbl.add(convertToMongoType(element, typeInformation));
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDbl;
|
return newDbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,7 +1009,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
|
|
||||||
private class MongoDbPropertyValueProvider implements PropertyValueProvider<MongoPersistentProperty> {
|
private class MongoDbPropertyValueProvider implements PropertyValueProvider<MongoPersistentProperty> {
|
||||||
|
|
||||||
private final DBObject source;
|
private final DBObjectAccessor source;
|
||||||
private final SpELExpressionEvaluator evaluator;
|
private final SpELExpressionEvaluator evaluator;
|
||||||
private final Object parent;
|
private final Object parent;
|
||||||
|
|
||||||
@@ -978,7 +1022,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
Assert.notNull(source);
|
Assert.notNull(source);
|
||||||
Assert.notNull(evaluator);
|
Assert.notNull(evaluator);
|
||||||
|
|
||||||
this.source = source;
|
this.source = new DBObjectAccessor(source);
|
||||||
this.evaluator = evaluator;
|
this.evaluator = evaluator;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
@@ -990,7 +1034,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
public <T> T getPropertyValue(MongoPersistentProperty property) {
|
public <T> T getPropertyValue(MongoPersistentProperty property) {
|
||||||
|
|
||||||
String expression = property.getSpelExpression();
|
String expression = property.getSpelExpression();
|
||||||
Object value = expression != null ? evaluator.evaluate(expression) : source.get(property.getFieldName());
|
Object value = expression != null ? evaluator.evaluate(expression) : source.get(property);
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1043,7 +1087,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
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, ((DBRef) value).fetch(), parent));
|
return (T) (rawType.equals(DBRef.class) ? value : read(type, readRef((DBRef) value), parent));
|
||||||
} else if (value instanceof BasicDBList) {
|
} else if (value instanceof BasicDBList) {
|
||||||
return (T) readCollectionOrArray(type, (BasicDBList) value, parent);
|
return (T) readCollectionOrArray(type, (BasicDBList) value, parent);
|
||||||
} else if (value instanceof DBObject) {
|
} else if (value instanceof DBObject) {
|
||||||
@@ -1052,4 +1096,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the fetch operation for the given {@link DBRef}.
|
||||||
|
*
|
||||||
|
* @param ref
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
DBObject readRef(DBRef ref) {
|
||||||
|
return ref.fetch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-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,21 +24,23 @@ 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.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class to contain useful converters for the usage with Mongo.
|
* Wrapper class to contain useful converters for the usage with Mongo.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
abstract class MongoConverters {
|
abstract class MongoConverters {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor to prevent instantiation.
|
* Private constructor to prevent instantiation.
|
||||||
*/
|
*/
|
||||||
private MongoConverters() {
|
private MongoConverters() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple singleton to convert {@link ObjectId}s to their {@link String} representation.
|
* Simple singleton to convert {@link ObjectId}s to their {@link String} representation.
|
||||||
@@ -147,4 +149,15 @@ abstract class MongoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReadingConverter
|
||||||
|
public static enum DBObjectToStringConverter implements Converter<DBObject, String> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(DBObject source) {
|
||||||
|
return source == null ? null : source.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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,19 +17,26 @@ 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.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
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.converter.Converter;
|
||||||
|
import org.springframework.data.mapping.Association;
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.mapping.PersistentEntity;
|
||||||
import org.springframework.data.mapping.PropertyPath;
|
import org.springframework.data.mapping.PropertyPath;
|
||||||
import org.springframework.data.mapping.PropertyReferenceException;
|
import org.springframework.data.mapping.PropertyReferenceException;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
||||||
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
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.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -44,11 +51,12 @@ import com.mongodb.DBRef;
|
|||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Patryk Wasik
|
* @author Patryk Wasik
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
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 String N_OR_PATTERN = "\\$.*or";
|
|
||||||
|
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
private final MongoConverter converter;
|
private final MongoConverter converter;
|
||||||
@@ -79,7 +87,7 @@ public class QueryMapper {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
|
public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
if (Keyword.isKeyword(query)) {
|
if (isNestedKeyword(query)) {
|
||||||
return getMappedKeyword(new Keyword(query), entity);
|
return getMappedKeyword(new Keyword(query), entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,51 +105,77 @@ public class QueryMapper {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keyword.isKeyword(key)) {
|
if (isKeyword(key)) {
|
||||||
result.putAll(getMappedKeyword(new Keyword(query, key), entity));
|
result.putAll(getMappedKeyword(new Keyword(query, key), entity));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Field field = entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext);
|
Field field = createPropertyField(entity, key, mappingContext);
|
||||||
|
Entry<String, Object> entry = getMappedObjectForField(field, query.get(key));
|
||||||
|
|
||||||
Object rawValue = query.get(key);
|
result.put(entry.getKey(), entry.getValue());
|
||||||
String newKey = field.getMappedKey();
|
|
||||||
|
|
||||||
if (Keyword.isKeyword(rawValue) && !field.isIdField()) {
|
|
||||||
Keyword keyword = new Keyword((DBObject) rawValue);
|
|
||||||
result.put(newKey, getMappedKeyword(field, keyword));
|
|
||||||
} else {
|
|
||||||
result.put(newKey, getMappedValue(field, rawValue));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the mapped object value for given field out of rawValue taking nested {@link Keyword}s into account
|
||||||
|
*
|
||||||
|
* @param field
|
||||||
|
* @param rawValue
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Entry<String, Object> getMappedObjectForField(Field field, Object rawValue) {
|
||||||
|
|
||||||
|
String key = field.getMappedKey();
|
||||||
|
Object value;
|
||||||
|
|
||||||
|
if (isNestedKeyword(rawValue) && !field.isIdField()) {
|
||||||
|
Keyword keyword = new Keyword((DBObject) rawValue);
|
||||||
|
value = getMappedKeyword(field, keyword);
|
||||||
|
} else {
|
||||||
|
value = getMappedValue(field, rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createMapEntry(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param entity
|
||||||
|
* @param key
|
||||||
|
* @param mappingContext
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Field createPropertyField(MongoPersistentEntity<?> entity, String key,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the given {@link DBObject} representing a keyword by mapping the keyword's value.
|
* Returns the given {@link DBObject} representing a keyword by mapping the keyword's value.
|
||||||
*
|
*
|
||||||
* @param query the {@link DBObject} representing a keyword (e.g. {@code $ne : … } )
|
* @param keyword the {@link DBObject} representing a keyword (e.g. {@code $ne : … } )
|
||||||
* @param entity
|
* @param entity
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity<?> entity) {
|
protected DBObject getMappedKeyword(Keyword keyword, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
// $or/$nor
|
// $or/$nor
|
||||||
if (query.key.matches(N_OR_PATTERN) || query.value instanceof Iterable) {
|
if (keyword.isOrOrNor() || keyword.hasIterableValue()) {
|
||||||
|
|
||||||
Iterable<?> conditions = (Iterable<?>) query.value;
|
Iterable<?> conditions = keyword.getValue();
|
||||||
BasicDBList newConditions = new BasicDBList();
|
BasicDBList newConditions = new BasicDBList();
|
||||||
|
|
||||||
for (Object condition : conditions) {
|
for (Object condition : conditions) {
|
||||||
newConditions.add(condition instanceof DBObject ? getMappedObject((DBObject) condition, entity)
|
newConditions.add(isDBObject(condition) ? getMappedObject((DBObject) condition, entity)
|
||||||
: convertSimpleOrDBObject(condition, entity));
|
: convertSimpleOrDBObject(condition, entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BasicDBObject(query.key, newConditions);
|
return new BasicDBObject(keyword.getKey(), newConditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BasicDBObject(query.key, convertSimpleOrDBObject(query.value, entity));
|
return new BasicDBObject(keyword.getKey(), convertSimpleOrDBObject(keyword.getValue(), entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,13 +185,15 @@ public class QueryMapper {
|
|||||||
* @param keyword
|
* @param keyword
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private DBObject getMappedKeyword(Field property, Keyword keyword) {
|
protected DBObject getMappedKeyword(Field property, Keyword keyword) {
|
||||||
|
|
||||||
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
||||||
Object value = needsAssociationConversion ? convertAssociation(keyword.value, property.getProperty())
|
Object value = keyword.getValue();
|
||||||
: getMappedValue(property.with(keyword.key), keyword.value);
|
|
||||||
|
|
||||||
return new BasicDBObject(keyword.key, value);
|
Object convertedValue = needsAssociationConversion ? convertAssociation(value, property) : getMappedValue(
|
||||||
|
property.with(keyword.getKey()), value);
|
||||||
|
|
||||||
|
return new BasicDBObject(keyword.key, convertedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,43 +205,61 @@ public class QueryMapper {
|
|||||||
* @param newKey the key the value will be bound to eventually
|
* @param newKey the key the value will be bound to eventually
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object getMappedValue(Field documentField, Object value) {
|
protected Object getMappedValue(Field documentField, Object value) {
|
||||||
|
|
||||||
if (documentField.isIdField()) {
|
if (documentField.isIdField()) {
|
||||||
|
|
||||||
if (value instanceof DBObject) {
|
if (isDBObject(value)) {
|
||||||
DBObject valueDbo = (DBObject) value;
|
DBObject valueDbo = (DBObject) value;
|
||||||
|
DBObject resultDbo = new BasicDBObject(valueDbo.toMap());
|
||||||
|
|
||||||
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
|
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
|
||||||
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
|
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
|
||||||
List<Object> ids = new ArrayList<Object>();
|
List<Object> ids = new ArrayList<Object>();
|
||||||
for (Object id : (Iterable<?>) valueDbo.get(inKey)) {
|
for (Object id : (Iterable<?>) valueDbo.get(inKey)) {
|
||||||
ids.add(convertId(id));
|
ids.add(convertId(id));
|
||||||
}
|
}
|
||||||
valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
|
resultDbo.put(inKey, ids.toArray(new Object[ids.size()]));
|
||||||
} else if (valueDbo.containsField("$ne")) {
|
} else if (valueDbo.containsField("$ne")) {
|
||||||
valueDbo.put("$ne", convertId(valueDbo.get("$ne")));
|
resultDbo.put("$ne", convertId(valueDbo.get("$ne")));
|
||||||
} else {
|
} else {
|
||||||
return getMappedObject((DBObject) value, null);
|
return getMappedObject(resultDbo, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return valueDbo;
|
return resultDbo;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return convertId(value);
|
return convertId(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keyword.isKeyword(value)) {
|
if (isNestedKeyword(value)) {
|
||||||
return getMappedKeyword(new Keyword((DBObject) value), null);
|
return getMappedKeyword(new Keyword((DBObject) value), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (documentField.isAssociation()) {
|
if (isAssociationConversionNecessary(documentField, value)) {
|
||||||
return convertAssociation(value, documentField.getProperty());
|
return convertAssociation(value, documentField);
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertSimpleOrDBObject(value, documentField.getPropertyEntity());
|
return convertSimpleOrDBObject(value, documentField.getPropertyEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given {@link Field} represents an association reference that together with the given value
|
||||||
|
* requires conversion to a {@link org.springframework.data.mongodb.core.mapping.DBRef} object. We check whether the
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param documentField
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected boolean isAssociationConversionNecessary(Field documentField, Object value) {
|
||||||
|
return documentField.isAssociation() && value != null
|
||||||
|
&& (documentField.getProperty().getActualType().isAssignableFrom(value.getClass()) //
|
||||||
|
|| documentField.getPropertyEntity().getIdProperty().getActualType().isAssignableFrom(value.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retriggers mapping if the given source is a {@link DBObject} or simply invokes the
|
* Retriggers mapping if the given source is a {@link DBObject} or simply invokes the
|
||||||
*
|
*
|
||||||
@@ -213,13 +267,13 @@ public class QueryMapper {
|
|||||||
* @param entity
|
* @param entity
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object convertSimpleOrDBObject(Object source, MongoPersistentEntity<?> entity) {
|
protected Object convertSimpleOrDBObject(Object source, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
if (source instanceof BasicDBList) {
|
if (source instanceof BasicDBList) {
|
||||||
return delegateConvertToMongoType(source, entity);
|
return delegateConvertToMongoType(source, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source instanceof DBObject) {
|
if (isDBObject(source)) {
|
||||||
return getMappedObject((DBObject) source, entity);
|
return getMappedObject((DBObject) source, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +292,10 @@ public class QueryMapper {
|
|||||||
return converter.convertToMongoType(source);
|
return converter.convertToMongoType(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Object convertAssociation(Object source, Field field) {
|
||||||
|
return convertAssociation(source, field.getProperty());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given source assuming it's actually an association to another object.
|
* Converts the given source assuming it's actually an association to another object.
|
||||||
*
|
*
|
||||||
@@ -245,16 +303,16 @@ public class QueryMapper {
|
|||||||
* @param property
|
* @param property
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object convertAssociation(Object source, MongoPersistentProperty property) {
|
protected Object convertAssociation(Object source, MongoPersistentProperty property) {
|
||||||
|
|
||||||
if (property == null || !property.isAssociation()) {
|
if (property == null || source == null || source instanceof DBRef || source instanceof DBObject) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
result.add(element instanceof DBRef ? element : converter.toDBRef(element, property));
|
result.add(createDbRefFor(element, property));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -263,13 +321,55 @@ public class QueryMapper {
|
|||||||
BasicDBObject result = new BasicDBObject();
|
BasicDBObject result = new BasicDBObject();
|
||||||
DBObject dbObject = (DBObject) source;
|
DBObject dbObject = (DBObject) source;
|
||||||
for (String key : dbObject.keySet()) {
|
for (String key : dbObject.keySet()) {
|
||||||
Object o = dbObject.get(key);
|
result.put(key, createDbRefFor(dbObject.get(key), property));
|
||||||
result.put(key, o instanceof DBRef ? o : converter.toDBRef(o, property));
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return source == null || source instanceof DBRef ? source : converter.toDBRef(source, property);
|
return createDbRefFor(source, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given value is a {@link DBObject}.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected final boolean isDBObject(Object value) {
|
||||||
|
return value instanceof DBObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Entry} for the given {@link Field} with the given value.
|
||||||
|
*
|
||||||
|
* @param field must not be {@literal null}.
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected final Entry<String, Object> createMapEntry(Field field, Object value) {
|
||||||
|
return createMapEntry(field.getMappedKey(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Entry} with the given key and value.
|
||||||
|
*
|
||||||
|
* @param key must not be {@literal null} or empty.
|
||||||
|
* @param value can be {@literal null}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Entry<String, Object> createMapEntry(String key, Object value) {
|
||||||
|
|
||||||
|
Assert.hasText(key, "Key must not be null or empty!");
|
||||||
|
return Collections.singletonMap(key, value).entrySet().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DBRef createDbRefFor(Object source, MongoPersistentProperty property) {
|
||||||
|
|
||||||
|
if (source instanceof DBRef) {
|
||||||
|
return (DBRef) source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converter.toDBRef(source, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,15 +389,50 @@ public class QueryMapper {
|
|||||||
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.
|
||||||
|
*
|
||||||
|
* @param candidate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected boolean isNestedKeyword(Object candidate) {
|
||||||
|
|
||||||
|
if (!(candidate instanceof BasicDBObject)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicDBObject dbObject = (BasicDBObject) candidate;
|
||||||
|
Set<String> keys = dbObject.keySet();
|
||||||
|
|
||||||
|
if (keys.size() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isKeyword(keys.iterator().next().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given {@link String} is a MongoDB keyword. The default implementation will check against the
|
||||||
|
* set of registered keywords returned by {@link #getKeywords()}.
|
||||||
|
*
|
||||||
|
* @param candidate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected boolean isKeyword(String candidate) {
|
||||||
|
return candidate.startsWith("$");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value object to capture a query keyword representation.
|
* Value object to capture a query keyword representation.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
private static class Keyword {
|
static class Keyword {
|
||||||
|
|
||||||
String key;
|
private static final String N_OR_PATTERN = "\\$.*or";
|
||||||
Object value;
|
|
||||||
|
private final String key;
|
||||||
|
private final Object value;
|
||||||
|
|
||||||
public Keyword(DBObject source, String key) {
|
public Keyword(DBObject source, String key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
@@ -322,25 +457,21 @@ public class QueryMapper {
|
|||||||
return "$exists".equalsIgnoreCase(key);
|
return "$exists".equalsIgnoreCase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean isOrOrNor() {
|
||||||
* Returns whether the given value actually represents a keyword. If this returns {@literal true} it's safe to call
|
return key.matches(N_OR_PATTERN);
|
||||||
* the constructor.
|
}
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isKeyword(Object value) {
|
|
||||||
|
|
||||||
if (value instanceof String) {
|
public boolean hasIterableValue() {
|
||||||
return ((String) value).startsWith("$");
|
return value instanceof Iterable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(value instanceof DBObject)) {
|
public String getKey() {
|
||||||
return false;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject dbObject = (DBObject) value;
|
@SuppressWarnings("unchecked")
|
||||||
return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$");
|
public <T> T getValue() {
|
||||||
|
return (T) value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +480,7 @@ public class QueryMapper {
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
private static class Field {
|
protected static class Field {
|
||||||
|
|
||||||
private static final String ID_KEY = "_id";
|
private static final String ID_KEY = "_id";
|
||||||
|
|
||||||
@@ -386,7 +517,9 @@ public class QueryMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying {@link MongoPersistentProperty} backing the field.
|
* Returns the underlying {@link MongoPersistentProperty} backing the field. For path traversals this will be the
|
||||||
|
* property that represents the value to handle. This means it'll be the leaf property for plain paths or the
|
||||||
|
* association property in case we refer to an association somewhere in the path.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -420,18 +553,36 @@ public class QueryMapper {
|
|||||||
public String getMappedKey() {
|
public String getMappedKey() {
|
||||||
return isIdField() ? ID_KEY : name;
|
return isIdField() ? ID_KEY : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the field references an association in case it refers to a nested field.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean containsAssociation() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Association<MongoPersistentProperty> getAssociation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension of {@link DocumentField} to be backed with mapping metadata.
|
* Extension of {@link DocumentField} to be backed with mapping metadata.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
private static class MetadataBackedField extends Field {
|
protected static class MetadataBackedField extends Field {
|
||||||
|
|
||||||
|
private static final String INVALID_ASSOCIATION_REFERENCE = "Invalid path reference %s! Associations can only be pointed to directly or via their id property!";
|
||||||
|
|
||||||
private final MongoPersistentEntity<?> entity;
|
private final MongoPersistentEntity<?> entity;
|
||||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
private final MongoPersistentProperty property;
|
private final MongoPersistentProperty property;
|
||||||
|
private final PersistentPropertyPath<MongoPersistentProperty> path;
|
||||||
|
private final Association<MongoPersistentProperty> association;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link MetadataBackedField} with the given name, {@link MongoPersistentEntity} and
|
* Creates a new {@link MetadataBackedField} with the given name, {@link MongoPersistentEntity} and
|
||||||
@@ -451,8 +602,9 @@ public class QueryMapper {
|
|||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.mappingContext = context;
|
this.mappingContext = context;
|
||||||
|
|
||||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(name);
|
this.path = getPath(name);
|
||||||
this.property = path == null ? null : path.getLeafProperty();
|
this.property = path == null ? null : path.getLeafProperty();
|
||||||
|
this.association = findAssociation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -486,7 +638,7 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MongoPersistentProperty getProperty() {
|
public MongoPersistentProperty getProperty() {
|
||||||
return property;
|
return association == null ? property : association.getInverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -505,9 +657,34 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isAssociation() {
|
public boolean isAssociation() {
|
||||||
|
return association != null;
|
||||||
|
}
|
||||||
|
|
||||||
MongoPersistentProperty property = getProperty();
|
/*
|
||||||
return property == null ? false : property.isAssociation();
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getAssociation()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Association<MongoPersistentProperty> getAssociation() {
|
||||||
|
return association;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the association property in the {@link PersistentPropertyPath}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private final Association<MongoPersistentProperty> findAssociation() {
|
||||||
|
|
||||||
|
if (this.path != null) {
|
||||||
|
for (MongoPersistentProperty p : this.path) {
|
||||||
|
if (p.isAssociation()) {
|
||||||
|
return p.getAssociation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -516,19 +693,57 @@ public class QueryMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getMappedKey() {
|
public String getMappedKey() {
|
||||||
|
return path == null ? name : path.toDotPath(getPropertyConverter());
|
||||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(name);
|
|
||||||
return path == null ? name : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String name) {
|
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link PersistentPropertyPath} for the given <code>pathExpression</code>.
|
||||||
|
*
|
||||||
|
* @param pathExpression
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpression) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PropertyPath path = PropertyPath.from(name, entity.getTypeInformation());
|
|
||||||
return mappingContext.getPersistentPropertyPath(path);
|
PropertyPath path = PropertyPath.from(pathExpression, entity.getTypeInformation());
|
||||||
|
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
|
||||||
|
|
||||||
|
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
|
||||||
|
boolean associationDetected = false;
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
|
||||||
|
MongoPersistentProperty property = iterator.next();
|
||||||
|
|
||||||
|
if (property.isAssociation()) {
|
||||||
|
associationDetected = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (associationDetected && !property.isIdProperty()) {
|
||||||
|
throw new MappingException(String.format(INVALID_ASSOCIATION_REFERENCE, pathExpression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return propertyPath;
|
||||||
} catch (PropertyReferenceException e) {
|
} catch (PropertyReferenceException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link Converter} to be used to created the mapped key. Default implementation will use
|
||||||
|
* {@link PropertyToFieldNameConverter}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||||
|
return PropertyToFieldNameConverter.INSTANCE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,16 +15,34 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.convert;
|
package org.springframework.data.mongodb.core.convert;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.data.mapping.Association;
|
||||||
|
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.PropertyToFieldNameConverter;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update.Modifier;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update.Modifiers;
|
||||||
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of {@link QueryMapper} that retains type information on the mongo types.
|
* A subclass of {@link QueryMapper} that retains type information on the mongo types.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class UpdateMapper extends QueryMapper {
|
public class UpdateMapper extends QueryMapper {
|
||||||
|
|
||||||
private final MongoWriter<?> converter;
|
private final MongoConverter converter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link UpdateMapper} using the given {@link MongoConverter}.
|
* Creates a new {@link UpdateMapper} using the given {@link MongoConverter}.
|
||||||
@@ -49,4 +67,196 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
return entity == null ? super.delegateConvertToMongoType(source, null) : converter.convertToMongoType(source,
|
return entity == null ? super.delegateConvertToMongoType(source, null) : converter.convertToMongoType(source,
|
||||||
entity.getTypeInformation());
|
entity.getTypeInformation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper#getMappedObjectForField(org.springframework.data.mongodb.core.convert.QueryMapper.Field, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Entry<String, Object> getMappedObjectForField(Field field, Object rawValue) {
|
||||||
|
|
||||||
|
if (isDBObject(rawValue)) {
|
||||||
|
return createMapEntry(field, convertSimpleOrDBObject(rawValue, field.getPropertyEntity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUpdateModifier(rawValue)) {
|
||||||
|
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
if (rawValue instanceof Modifier) {
|
||||||
|
|
||||||
|
value = getMappedValue((Modifier) rawValue);
|
||||||
|
|
||||||
|
} else if (rawValue instanceof Modifiers) {
|
||||||
|
|
||||||
|
DBObject modificationOperations = new BasicDBObject();
|
||||||
|
|
||||||
|
for (Modifier modifier : ((Modifiers) rawValue).getModifiers()) {
|
||||||
|
modificationOperations.putAll(getMappedValue(modifier).toMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
value = modificationOperations;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(String.format("Unable to map value of type '%s'!", rawValue.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return createMapEntry(field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper#isAssociationConversionNecessary(org.springframework.data.mongodb.core.convert.QueryMapper.Field, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isAssociationConversionNecessary(Field documentField, Object value) {
|
||||||
|
return super.isAssociationConversionNecessary(documentField, value) || documentField.containsAssociation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUpdateModifier(Object value) {
|
||||||
|
return value instanceof Modifier || value instanceof Modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DBObject getMappedValue(Modifier modifier) {
|
||||||
|
|
||||||
|
Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT);
|
||||||
|
return new BasicDBObject(modifier.getKey(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper#createPropertyField(org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.String, org.springframework.data.mapping.context.MappingContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Field createPropertyField(MongoPersistentEntity<?> entity, String key,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
|
||||||
|
return entity == null ? super.createPropertyField(entity, key, mappingContext) : //
|
||||||
|
new MetadataBackedUpdateField(entity, key, mappingContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link MetadataBackedField} that handles {@literal $} paths inside a field key. We clean up an update key
|
||||||
|
* containing a {@literal $} before handing it to the super class to make sure property lookups and transformations
|
||||||
|
* continue to work as expected. We provide a custom property converter to re-applied the cleaned up {@literal $}s
|
||||||
|
* when constructing the mapped key.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class MetadataBackedUpdateField extends MetadataBackedField {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link MetadataBackedField} with the given {@link MongoPersistentEntity}, key and
|
||||||
|
* {@link MappingContext}. We clean up the key before handing it up to the super class to make sure it continues to
|
||||||
|
* work as expected.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param key must not be {@literal null} or empty.
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MetadataBackedUpdateField(MongoPersistentEntity<?> entity, String key,
|
||||||
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||||
|
|
||||||
|
super(key.replaceAll("\\.\\$", ""), entity, mappingContext);
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getMappedKey()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getMappedKey() {
|
||||||
|
return this.getPath() == null ? key : super.getMappedKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getPropertyConverter()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||||
|
return isAssociation() ? new AssociationConverter(getAssociation()) : 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)
|
||||||
|
* @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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special {@link Converter} for {@link MongoPersistentProperty} instances that will concatenate the {@literal $}
|
||||||
|
* contained in the source update key.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
||||||
|
|
||||||
|
private final Iterator<String> iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
||||||
|
*
|
||||||
|
* @param updateKey must not be {@literal null} or empty.
|
||||||
|
*/
|
||||||
|
public UpdatePropertyConverter(String updateKey) {
|
||||||
|
|
||||||
|
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
||||||
|
|
||||||
|
this.iterator = Arrays.asList(updateKey.split("\\.")).iterator();
|
||||||
|
this.iterator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String convert(MongoPersistentProperty property) {
|
||||||
|
|
||||||
|
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||||
|
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -16,44 +16,31 @@
|
|||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
import org.springframework.data.geo.Point;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a geospatial box value
|
* 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 Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class Box implements Shape {
|
@Deprecated
|
||||||
|
public class Box extends org.springframework.data.geo.Box implements Shape {
|
||||||
|
|
||||||
@Field(order = 10)
|
public static final String COMMAND = "$box";
|
||||||
private final Point first;
|
|
||||||
@Field(order = 20)
|
|
||||||
private final Point second;
|
|
||||||
|
|
||||||
public Box(Point lowerLeft, Point upperRight) {
|
public Box(Point lowerLeft, Point upperRight) {
|
||||||
Assert.notNull(lowerLeft);
|
super(lowerLeft, upperRight);
|
||||||
Assert.notNull(upperRight);
|
|
||||||
this.first = lowerLeft;
|
|
||||||
this.second = upperRight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Box(double[] lowerLeft, double[] upperRight) {
|
public Box(double[] lowerLeft, double[] upperRight) {
|
||||||
Assert.isTrue(lowerLeft.length == 2, "Point array has to have 2 elements!");
|
super(lowerLeft, upperRight);
|
||||||
Assert.isTrue(upperRight.length == 2, "Point array has to have 2 elements!");
|
|
||||||
this.first = new Point(lowerLeft[0], lowerLeft[1]);
|
|
||||||
this.second = new Point(upperRight[0], upperRight[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point getLowerLeft() {
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point getUpperRight() {
|
|
||||||
return second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -61,46 +48,28 @@ public class Box implements Shape {
|
|||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||||
*/
|
*/
|
||||||
public List<? extends Object> asList() {
|
public List<? extends Object> asList() {
|
||||||
|
|
||||||
List<List<Double>> list = new ArrayList<List<Double>>();
|
List<List<Double>> list = new ArrayList<List<Double>>();
|
||||||
list.add(getLowerLeft().asList());
|
|
||||||
list.add(getUpperRight().asList());
|
list.add(Arrays.asList(getFirst().getX(), getFirst().getY()));
|
||||||
|
list.add(Arrays.asList(getSecond().getX(), getSecond().getY()));
|
||||||
|
|
||||||
return list;
|
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)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||||
*/
|
*/
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return "$box";
|
return COMMAND;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Box [%s, %s]", first, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
|
|
||||||
int result = 31;
|
|
||||||
result += 17 * first.hashCode();
|
|
||||||
result += 17 * second.hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Box that = (Box) obj;
|
|
||||||
return this.first.equals(that.first) && this.second.equals(that.second);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -16,19 +16,32 @@
|
|||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
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;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a geospatial circle value
|
* 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 Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @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 class Circle implements Shape {
|
||||||
|
|
||||||
|
public static final String COMMAND = "$center";
|
||||||
|
|
||||||
private final Point center;
|
private final Point center;
|
||||||
private final double radius;
|
private final double radius;
|
||||||
|
|
||||||
@@ -49,7 +62,8 @@ public class Circle implements Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Circle} from the given coordinates and radius.
|
* Creates a new {@link Circle} from the given coordinates and radius as {@link Distance} with a
|
||||||
|
* {@link Metrics#NEUTRAL}.
|
||||||
*
|
*
|
||||||
* @param centerX
|
* @param centerX
|
||||||
* @param centerY
|
* @param centerY
|
||||||
@@ -82,9 +96,11 @@ public class Circle implements Shape {
|
|||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||||
*/
|
*/
|
||||||
public List<Object> asList() {
|
public List<Object> asList() {
|
||||||
|
|
||||||
List<Object> result = new ArrayList<Object>();
|
List<Object> result = new ArrayList<Object>();
|
||||||
result.add(getCenter().asList());
|
result.add(Arrays.asList(getCenter().getX(), getCenter().getY()));
|
||||||
result.add(getRadius());
|
result.add(getRadius());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +109,7 @@ public class Circle implements Shape {
|
|||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||||
*/
|
*/
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return "$center";
|
return COMMAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -18,11 +18,13 @@ package org.springframework.data.mongodb.core.geo;
|
|||||||
/**
|
/**
|
||||||
* Value object to create custom {@link Metric}s on the fly.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class CustomMetric implements Metric {
|
@Deprecated
|
||||||
|
public class CustomMetric extends org.springframework.data.geo.CustomMetric implements Metric {
|
||||||
private final double multiplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a custom {@link Metric} using the given multiplier.
|
* Creates a custom {@link Metric} using the given multiplier.
|
||||||
@@ -30,14 +32,6 @@ public class CustomMetric implements Metric {
|
|||||||
* @param multiplier
|
* @param multiplier
|
||||||
*/
|
*/
|
||||||
public CustomMetric(double multiplier) {
|
public CustomMetric(double multiplier) {
|
||||||
this.multiplier = multiplier;
|
super(multiplier);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.geo.Metric#getMultiplier()
|
|
||||||
*/
|
|
||||||
public double getMultiplier() {
|
|
||||||
return multiplier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -15,17 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.data.geo.Metric;
|
||||||
|
import org.springframework.data.geo.Metrics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value object to represent distances in a given metric.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class Distance {
|
@Deprecated
|
||||||
|
public class Distance extends org.springframework.data.geo.Distance {
|
||||||
private final double value;
|
|
||||||
private final Metric metric;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Distance}.
|
* Creates a new {@link Distance}.
|
||||||
@@ -36,110 +38,7 @@ public class Distance {
|
|||||||
this(value, Metrics.NEUTRAL);
|
this(value, Metrics.NEUTRAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Distance} with the given {@link Metric}.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* @param metric
|
|
||||||
*/
|
|
||||||
public Distance(double value, Metric metric) {
|
public Distance(double value, Metric metric) {
|
||||||
this.value = value;
|
super(value, metric);
|
||||||
this.metric = metric == null ? Metrics.NEUTRAL : metric;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the value
|
|
||||||
*/
|
|
||||||
public double getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the normalized value regarding the underlying {@link Metric}.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public double getNormalizedValue() {
|
|
||||||
return value / metric.getMultiplier();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the metric
|
|
||||||
*/
|
|
||||||
public Metric getMetric() {
|
|
||||||
return metric;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given distance to the current one. The resulting {@link Distance} will be in the same metric as the
|
|
||||||
* current one.
|
|
||||||
*
|
|
||||||
* @param other
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Distance add(Distance other) {
|
|
||||||
double newNormalizedValue = getNormalizedValue() + other.getNormalizedValue();
|
|
||||||
return new Distance(newNormalizedValue * metric.getMultiplier(), metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given {@link Distance} to the current one and forces the result to be in a given {@link Metric}.
|
|
||||||
*
|
|
||||||
* @param other
|
|
||||||
* @param metric
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Distance add(Distance other, Metric metric) {
|
|
||||||
double newLeft = getNormalizedValue() * metric.getMultiplier();
|
|
||||||
double newRight = other.getNormalizedValue() * metric.getMultiplier();
|
|
||||||
return new Distance(newLeft + newRight, metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Distance that = (Distance) obj;
|
|
||||||
|
|
||||||
return this.value == that.value && ObjectUtils.nullSafeEquals(this.metric, that.metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = 17;
|
|
||||||
result += 31 * Double.doubleToLongBits(value);
|
|
||||||
result += 31 * ObjectUtils.nullSafeHashCode(metric);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append(value);
|
|
||||||
|
|
||||||
if (metric != Metrics.NEUTRAL) {
|
|
||||||
builder.append(" ").append(metric.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -16,19 +16,21 @@
|
|||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
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
|
* Custom {@link Page} to carry the average distance retrieved from the {@link GeoResults} the {@link GeoPage} is set up
|
||||||
* from.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class GeoPage<T> extends PageImpl<GeoResult<T>> {
|
@Deprecated
|
||||||
|
public class GeoPage<T> extends org.springframework.data.geo.GeoPage<T> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 23421312312412L;
|
private static final long serialVersionUID = 23421312312412L;
|
||||||
private final Distance averageDistance;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
|
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
|
||||||
@@ -36,8 +38,7 @@ public class GeoPage<T> extends PageImpl<GeoResult<T>> {
|
|||||||
* @param content must not be {@literal null}.
|
* @param content must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public GeoPage(GeoResults<T> results) {
|
public GeoPage(GeoResults<T> results) {
|
||||||
super(results.getContent());
|
super(results);
|
||||||
this.averageDistance = results.getAverageDistance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,16 +49,6 @@ public class GeoPage<T> extends PageImpl<GeoResult<T>> {
|
|||||||
* @param total
|
* @param total
|
||||||
*/
|
*/
|
||||||
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
|
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
|
||||||
super(results.getContent(), pageable, total);
|
super(results, pageable, total);
|
||||||
this.averageDistance = results.getAverageDistance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the average distance of the underlying results.
|
|
||||||
*
|
|
||||||
* @return the averageDistance
|
|
||||||
*/
|
|
||||||
public Distance getAverageDistance() {
|
|
||||||
return averageDistance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-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,17 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calue object capturing some arbitrary object plus a distance.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class GeoResult<T> {
|
@Deprecated
|
||||||
|
public class GeoResult<T> extends org.springframework.data.geo.GeoResult<T> {
|
||||||
private final T content;
|
|
||||||
private final Distance distance;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link GeoResult} for the given content and distance.
|
* Creates a new {@link GeoResult} for the given content and distance.
|
||||||
@@ -34,69 +33,6 @@ public class GeoResult<T> {
|
|||||||
* @param distance must not be {@literal null}.
|
* @param distance must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public GeoResult(T content, Distance distance) {
|
public GeoResult(T content, Distance distance) {
|
||||||
Assert.notNull(content);
|
super(content, distance);
|
||||||
Assert.notNull(distance);
|
|
||||||
this.content = content;
|
|
||||||
this.distance = distance;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Returns the actual content object.
|
|
||||||
*
|
|
||||||
* @return the content
|
|
||||||
*/
|
|
||||||
public T getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the distance the actual content object has from the origin.
|
|
||||||
*
|
|
||||||
* @return the distance
|
|
||||||
*/
|
|
||||||
public Distance getDistance() {
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeoResult<?> that = (GeoResult<?>) obj;
|
|
||||||
|
|
||||||
return this.content.equals(that.content) && this.distance.equals(that.distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
|
|
||||||
int result = 17;
|
|
||||||
result += 31 * distance.hashCode();
|
|
||||||
result += 31 * content.hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("GeoResult [content: %s, distance: %s, ]", content.toString(), distance.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-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,23 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.geo;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.data.geo.Distance;
|
||||||
import org.springframework.util.StringUtils;
|
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.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class GeoResults<T> implements Iterable<GeoResult<T>> {
|
@Deprecated
|
||||||
|
public class GeoResults<T> extends org.springframework.data.geo.GeoResults<T> {
|
||||||
private final List<GeoResult<T>> results;
|
|
||||||
private final Distance averageDistance;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link GeoResults} instance manually calculating the average distance from the distance values of the
|
* Creates a new {@link GeoResults} instance manually calculating the average distance from the distance values of the
|
||||||
@@ -39,12 +39,12 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
|
|||||||
*
|
*
|
||||||
* @param results must not be {@literal null}.
|
* @param results must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public GeoResults(List<GeoResult<T>> results) {
|
public GeoResults(List<? extends GeoResult<T>> results) {
|
||||||
this(results, (Metric) null);
|
super(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeoResults(List<GeoResult<T>> results, Metric metric) {
|
public GeoResults(List<? extends GeoResult<T>> results, Metric metric) {
|
||||||
this(results, calculateAverageDistance(results, metric));
|
super(results, metric);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,92 +54,7 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
|
|||||||
* @param averageDistance
|
* @param averageDistance
|
||||||
*/
|
*/
|
||||||
@PersistenceConstructor
|
@PersistenceConstructor
|
||||||
public GeoResults(List<GeoResult<T>> results, Distance averageDistance) {
|
public GeoResults(List<? extends GeoResult<T>> results, Distance averageDistance) {
|
||||||
Assert.notNull(results);
|
super(results, averageDistance);
|
||||||
this.results = results;
|
|
||||||
this.averageDistance = averageDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the average distance of all {@link GeoResult}s in this list.
|
|
||||||
*
|
|
||||||
* @return the averageDistance
|
|
||||||
*/
|
|
||||||
public Distance getAverageDistance() {
|
|
||||||
return averageDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Iterable#iterator()
|
|
||||||
*/
|
|
||||||
public Iterator<GeoResult<T>> iterator() {
|
|
||||||
return results.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the actual
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<GeoResult<T>> getContent() {
|
|
||||||
return Collections.unmodifiableList(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeoResults<?> that = (GeoResults<?>) obj;
|
|
||||||
|
|
||||||
return this.results.equals(that.results) && this.averageDistance == that.averageDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = 17;
|
|
||||||
result += 31 * results.hashCode();
|
|
||||||
result += 31 * averageDistance.hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("GeoResults: [averageDistance: %s, results: %s]", averageDistance.toString(),
|
|
||||||
StringUtils.collectionToCommaDelimitedString(results));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
|
|
||||||
|
|
||||||
if (results.isEmpty()) {
|
|
||||||
return new Distance(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
double averageDistance = 0;
|
|
||||||
|
|
||||||
for (GeoResult<?> result : results) {
|
|
||||||
averageDistance += result.getDistance().getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Distance(averageDistance / results.size(), metric);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for {@link Metric}s that can be applied to a base scale.
|
* 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
|
||||||
*/
|
*/
|
||||||
public interface Metric {
|
@Deprecated
|
||||||
|
public interface Metric extends org.springframework.data.geo.Metric {}
|
||||||
/**
|
|
||||||
* Returns the multiplier to calculate metrics values from a base scale.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
double getMultiplier();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||||
@@ -5,11 +20,17 @@ import org.springframework.data.mongodb.core.query.NearQuery;
|
|||||||
/**
|
/**
|
||||||
* Commonly used {@link Metrics} for {@link NearQuery}s.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public enum Metrics implements Metric {
|
public enum Metrics implements Metric {
|
||||||
|
|
||||||
KILOMETERS(6378.137), MILES(3963.191), NEUTRAL(1);
|
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 final double multiplier;
|
||||||
|
|
||||||
@@ -24,4 +45,4 @@ public enum Metrics implements Metric {
|
|||||||
public double getMultiplier() {
|
public double getMultiplier() {
|
||||||
return multiplier;
|
return multiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -19,85 +19,37 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a geospatial point value.
|
* 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 Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class Point {
|
@Deprecated
|
||||||
|
public class Point extends org.springframework.data.geo.Point {
|
||||||
@Field(order = 10)
|
|
||||||
private final double x;
|
|
||||||
@Field(order = 20)
|
|
||||||
private final double y;
|
|
||||||
|
|
||||||
@PersistenceConstructor
|
@PersistenceConstructor
|
||||||
public Point(double x, double y) {
|
public Point(double x, double y) {
|
||||||
this.x = x;
|
super(x, y);
|
||||||
this.y = y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point(Point point) {
|
public Point(org.springframework.data.geo.Point point) {
|
||||||
Assert.notNull(point);
|
super(point);
|
||||||
this.x = point.x;
|
|
||||||
this.y = point.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getY() {
|
|
||||||
return y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public double[] asArray() {
|
public double[] asArray() {
|
||||||
return new double[] { x, y };
|
return new double[] { getX(), getY() };
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Double> asList() {
|
public List<Double> asList() {
|
||||||
return Arrays.asList(x, y);
|
return asList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static List<Double> asList(org.springframework.data.geo.Point point) {
|
||||||
public int hashCode() {
|
return Arrays.asList(point.getX(), point.getY());
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
long temp;
|
|
||||||
temp = Double.doubleToLongBits(x);
|
|
||||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
|
||||||
temp = Double.doubleToLongBits(y);
|
|
||||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Point other = (Point) obj;
|
|
||||||
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Point [latitude=%f, longitude=%f]", x, y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-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,19 +17,22 @@ package org.springframework.data.mongodb.core.geo;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.data.geo.Point;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple value object to represent a {@link Polygon}.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class Polygon implements Shape, Iterable<Point> {
|
@Deprecated
|
||||||
|
public class Polygon extends org.springframework.data.geo.Polygon implements Shape {
|
||||||
|
|
||||||
private final List<Point> points;
|
public static final String COMMAND = "$polygon";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Polygon} for the given Points.
|
* Creates a new {@link Polygon} for the given Points.
|
||||||
@@ -39,31 +42,17 @@ public class Polygon implements Shape, Iterable<Point> {
|
|||||||
* @param z
|
* @param z
|
||||||
* @param others
|
* @param others
|
||||||
*/
|
*/
|
||||||
public Polygon(Point x, Point y, Point z, Point... others) {
|
public <P extends Point> Polygon(P x, P y, P z, P... others) {
|
||||||
|
super(x, y, z, others);
|
||||||
Assert.notNull(x);
|
|
||||||
Assert.notNull(y);
|
|
||||||
Assert.notNull(z);
|
|
||||||
Assert.notNull(others);
|
|
||||||
|
|
||||||
this.points = new ArrayList<Point>(3 + others.length);
|
|
||||||
this.points.addAll(Arrays.asList(x, y, z));
|
|
||||||
this.points.addAll(Arrays.asList(others));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* (non-Javadoc)
|
* Creates a new {@link Polygon} for the given Points.
|
||||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
*
|
||||||
|
* @param points
|
||||||
*/
|
*/
|
||||||
public List<List<Double>> asList() {
|
public <P extends Point> Polygon(List<P> points) {
|
||||||
|
super(points);
|
||||||
List<List<Double>> result = new ArrayList<List<Double>>();
|
|
||||||
|
|
||||||
for (Point point : points) {
|
|
||||||
result.add(point.asList());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -71,43 +60,33 @@ public class Polygon implements Shape, Iterable<Point> {
|
|||||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||||
*/
|
*/
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return "$polygon";
|
return COMMAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see java.lang.Iterable#iterator()
|
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||||
*/
|
|
||||||
public Iterator<Point> iterator() {
|
|
||||||
return this.points.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public List<? extends Object> asList() {
|
||||||
|
return asList(this);
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygon that = (Polygon) obj;
|
|
||||||
|
|
||||||
return this.points.equals(that.points);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* (non-Javadoc)
|
* Returns a {@link List} of x,y-coordinate tuples of {@link Point}s from the given {@link Polygon}.
|
||||||
* @see java.lang.Object#hashCode()
|
*
|
||||||
|
* @param polygon
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
public static List<? extends Object> asList(org.springframework.data.geo.Polygon polygon) {
|
||||||
public int hashCode() {
|
|
||||||
return points.hashCode();
|
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,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -20,9 +20,13 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Common interface for all shapes. Allows building MongoDB representations of them.
|
* 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 Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public interface Shape {
|
@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
|
* Returns the {@link Shape} as a list of usually {@link Double} or {@link List}s of {@link Double}s. Wildcard bound
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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.geo;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
|
import org.springframework.data.geo.Circle;
|
||||||
|
import org.springframework.data.geo.Distance;
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a geospatial sphere value.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class Sphere implements Shape {
|
||||||
|
|
||||||
|
public static final String COMMAND = "$centerSphere";
|
||||||
|
private final Point center;
|
||||||
|
private final Distance radius;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Sphere around the given center {@link Point} with the given radius.
|
||||||
|
*
|
||||||
|
* @param center must not be {@literal null}.
|
||||||
|
* @param radius must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
@PersistenceConstructor
|
||||||
|
public Sphere(Point center, Distance radius) {
|
||||||
|
|
||||||
|
Assert.notNull(center);
|
||||||
|
Assert.notNull(radius);
|
||||||
|
Assert.isTrue(radius.getValue() >= 0, "Radius must not be negative!");
|
||||||
|
|
||||||
|
this.center = center;
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Sphere around the given center {@link Point} with the given radius.
|
||||||
|
*
|
||||||
|
* @param center
|
||||||
|
* @param radius
|
||||||
|
*/
|
||||||
|
public Sphere(Point center, double radius) {
|
||||||
|
this(center, new Distance(radius));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Sphere from the given {@link Circle}.
|
||||||
|
*
|
||||||
|
* @param circle
|
||||||
|
*/
|
||||||
|
public Sphere(Circle circle) {
|
||||||
|
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}.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
public org.springframework.data.mongodb.core.geo.Point getCenter() {
|
||||||
|
return new org.springframework.data.mongodb.core.geo.Point(this.center);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the radius of the {@link Circle}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Distance getRadius() {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Sphere [center=%s, radius=%s]", 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 || !(obj instanceof Sphere)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sphere that = (Sphere) obj;
|
||||||
|
|
||||||
|
return this.center.equals(that.center) && this.radius.equals(that.radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result += 31 * center.hashCode();
|
||||||
|
result += 31 * radius.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<? extends Object> asList() {
|
||||||
|
return Arrays.asList(Arrays.asList(center.getX(), center.getY()), this.radius.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCommand() {
|
||||||
|
return COMMAND;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Support for MongoDB geo-spatial queries.
|
* Support for MongoDB geo-spatial queries.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -51,10 +51,24 @@ public @interface CompoundIndex {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
IndexDirection direction() default IndexDirection.ASCENDING;
|
IndexDirection direction() default IndexDirection.ASCENDING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-unique/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean unique() default false;
|
boolean unique() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true index will skip over any document that is missing the indexed field.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-sparse/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean sparse() default false;
|
boolean sparse() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean dropDups() default false;
|
boolean dropDups() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geoposatial index type.
|
||||||
|
*
|
||||||
|
* @author Laurent Canet
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
public enum GeoSpatialIndexType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple 2-Dimensional index for legacy-format points.
|
||||||
|
*/
|
||||||
|
GEO_2D,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2D Index for GeoJSON-formatted data over a sphere. Only available in Mongo 2.4.
|
||||||
|
*/
|
||||||
|
GEO_2DSPHERE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An haystack index for grouping results over small results.
|
||||||
|
*/
|
||||||
|
GEO_HAYSTACK
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 by the original author(s).
|
* Copyright 2010-2013 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.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* 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.index;
|
package org.springframework.data.mongodb.core.index;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
@@ -24,7 +23,8 @@ import java.lang.annotation.Target;
|
|||||||
/**
|
/**
|
||||||
* Mark a field to be indexed using MongoDB's geospatial indexing feature.
|
* Mark a field to be indexed using MongoDB's geospatial indexing feature.
|
||||||
*
|
*
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
* @author Jon Brisbin
|
||||||
|
* @author Laurent Canet
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@@ -65,4 +65,27 @@ public @interface GeoSpatialIndexed {
|
|||||||
*/
|
*/
|
||||||
int bits() default 26;
|
int bits() default 26;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the geospatial index. Default is {@link GeoSpatialIndexType#GEO_2D}
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
GeoSpatialIndexType type() default GeoSpatialIndexType.GEO_2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bucket size for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes, in coordinate units.
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
double bucketSize() default 1.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the additional field to use for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes
|
||||||
|
*
|
||||||
|
* @since 1.4
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String additionalField() default "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 the original author or authors.
|
* Copyright 2010-2013 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.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package org.springframework.data.mongodb.core.index;
|
package org.springframework.data.mongodb.core.index;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
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;
|
||||||
@@ -25,14 +26,18 @@ import com.mongodb.DBObject;
|
|||||||
*
|
*
|
||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Laurent Canet
|
||||||
*/
|
*/
|
||||||
public class GeospatialIndex implements IndexDefinition {
|
public class GeospatialIndex implements IndexDefinition {
|
||||||
|
|
||||||
private final String field;
|
private final String field;
|
||||||
private String name;
|
private String name;
|
||||||
private Integer min = null;
|
private Integer min;
|
||||||
private Integer max = null;
|
private Integer max;
|
||||||
private Integer bits = null;
|
private Integer bits;
|
||||||
|
private GeoSpatialIndexType type = GeoSpatialIndexType.GEO_2D;
|
||||||
|
private Double bucketSize = 1.0;
|
||||||
|
private String additionalField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link GeospatialIndex} for the given field.
|
* Creates a new {@link GeospatialIndex} for the given field.
|
||||||
@@ -40,52 +45,146 @@ public class GeospatialIndex implements IndexDefinition {
|
|||||||
* @param field must not be empty or {@literal null}.
|
* @param field must not be empty or {@literal null}.
|
||||||
*/
|
*/
|
||||||
public GeospatialIndex(String field) {
|
public GeospatialIndex(String field) {
|
||||||
Assert.hasText(field);
|
|
||||||
|
Assert.hasText(field, "Field must have text!");
|
||||||
|
|
||||||
this.field = field;
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param min
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public GeospatialIndex withMin(int min) {
|
public GeospatialIndex withMin(int min) {
|
||||||
this.min = Integer.valueOf(min);
|
this.min = Integer.valueOf(min);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param max
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public GeospatialIndex withMax(int max) {
|
public GeospatialIndex withMax(int max) {
|
||||||
this.max = Integer.valueOf(max);
|
this.max = Integer.valueOf(max);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bits
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public GeospatialIndex withBits(int bits) {
|
public GeospatialIndex withBits(int bits) {
|
||||||
this.bits = Integer.valueOf(bits);
|
this.bits = Integer.valueOf(bits);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public GeospatialIndex typed(GeoSpatialIndexType type) {
|
||||||
|
|
||||||
|
Assert.notNull(type, "Type must not be null!");
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bucketSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public GeospatialIndex withBucketSize(double bucketSize) {
|
||||||
|
this.bucketSize = bucketSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fieldName.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public GeospatialIndex withAdditionalField(String fieldName) {
|
||||||
|
this.additionalField = fieldName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public DBObject getIndexKeys() {
|
public DBObject getIndexKeys() {
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
dbo.put(field, "2d");
|
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case GEO_2D:
|
||||||
|
dbo.put(field, "2d");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEO_2DSPHERE:
|
||||||
|
dbo.put(field, "2dsphere");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEO_HAYSTACK:
|
||||||
|
dbo.put(field, "geoHaystack");
|
||||||
|
if (!StringUtils.hasText(additionalField)) {
|
||||||
|
throw new IllegalArgumentException("When defining geoHaystack index, an additionnal field must be defined");
|
||||||
|
}
|
||||||
|
dbo.put(additionalField, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported geospatial index " + type);
|
||||||
|
}
|
||||||
|
|
||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DBObject getIndexOptions() {
|
public DBObject getIndexOptions() {
|
||||||
if (name == null && min == null && max == null) {
|
|
||||||
|
if (name == null && min == null && max == null && bucketSize == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
dbo.put("name", name);
|
dbo.put("name", name);
|
||||||
}
|
}
|
||||||
if (min != null) {
|
|
||||||
dbo.put("min", min);
|
switch (type) {
|
||||||
}
|
|
||||||
if (max != null) {
|
case GEO_2D:
|
||||||
dbo.put("max", max);
|
|
||||||
}
|
if (min != null) {
|
||||||
if (bits != null) {
|
dbo.put("min", min);
|
||||||
dbo.put("bits", bits);
|
}
|
||||||
|
if (max != null) {
|
||||||
|
dbo.put("max", max);
|
||||||
|
}
|
||||||
|
if (bits != null) {
|
||||||
|
dbo.put("bits", bits);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEO_2DSPHERE:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEO_HAYSTACK:
|
||||||
|
|
||||||
|
if (bucketSize != null) {
|
||||||
|
dbo.put("bucketSize", bucketSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ public class Index implements IndexDefinition {
|
|||||||
|
|
||||||
private boolean sparse = false;
|
private boolean sparse = false;
|
||||||
|
|
||||||
public Index() {
|
public Index() {}
|
||||||
}
|
|
||||||
|
|
||||||
public Index(String key, Direction direction) {
|
public Index(String key, Direction direction) {
|
||||||
fieldSpec.put(key, direction);
|
fieldSpec.put(key, direction);
|
||||||
@@ -83,16 +82,33 @@ public class Index implements IndexDefinition {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reject all documents that contain a duplicate value for the indexed field.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-unique/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Index unique() {
|
public Index unique() {
|
||||||
this.unique = true;
|
this.unique = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip over any document that is missing the indexed field.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-sparse/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Index sparse() {
|
public Index sparse() {
|
||||||
this.sparse = true;
|
this.sparse = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping
|
||||||
|
* @param duplicates
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Index unique(Duplicates duplicates) {
|
public Index unique(Duplicates duplicates) {
|
||||||
if (duplicates == Duplicates.DROP) {
|
if (duplicates == Duplicates.DROP) {
|
||||||
this.dropDuplicates = true;
|
this.dropDuplicates = true;
|
||||||
|
|||||||
@@ -32,16 +32,42 @@ import java.lang.annotation.Target;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Indexed {
|
public @interface Indexed {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true reject all documents that contain a duplicate value for the indexed field.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-unique/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean unique() default false;
|
boolean unique() default false;
|
||||||
|
|
||||||
IndexDirection direction() default IndexDirection.ASCENDING;
|
IndexDirection direction() default IndexDirection.ASCENDING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true index will skip over any document that is missing the indexed field.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-sparse/
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean sparse() default false;
|
boolean sparse() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see http://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean dropDups() default false;
|
boolean dropDups() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index name.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colleciton name for index to be created on.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
String collection() default "";
|
String collection() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.index;
|
package org.springframework.data.mongodb.core.index;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -45,11 +44,12 @@ import com.mongodb.util.JSON;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
* @author Johno Crawford
|
* @author Johno Crawford
|
||||||
|
* @author Laurent Canet
|
||||||
*/
|
*/
|
||||||
public class MongoPersistentEntityIndexCreator implements
|
public class MongoPersistentEntityIndexCreator implements
|
||||||
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MongoPersistentEntityIndexCreator.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(MongoPersistentEntityIndexCreator.class);
|
||||||
|
|
||||||
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;
|
||||||
@@ -96,8 +96,8 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
protected void checkForIndexes(final MongoPersistentEntity<?> entity) {
|
protected void checkForIndexes(final MongoPersistentEntity<?> entity) {
|
||||||
final Class<?> type = entity.getType();
|
final Class<?> type = entity.getType();
|
||||||
if (!classesSeen.containsKey(type)) {
|
if (!classesSeen.containsKey(type)) {
|
||||||
if (log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
log.debug("Analyzing class " + type + " for index information.");
|
LOGGER.debug("Analyzing class " + type + " for index information.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure indexes get created
|
// Make sure indexes get created
|
||||||
@@ -111,29 +111,27 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
ensureIndex(indexColl, index.name(), definition, index.unique(), index.dropDups(), index.sparse(),
|
ensureIndex(indexColl, index.name(), definition, index.unique(), index.dropDups(), index.sparse(),
|
||||||
index.background(), index.expireAfterSeconds());
|
index.background(), index.expireAfterSeconds());
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
log.debug("Created compound index " + index);
|
LOGGER.debug("Created compound index " + index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||||
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
|
public void doWithPersistentProperty(MongoPersistentProperty property) {
|
||||||
|
|
||||||
Field field = persistentProperty.getField();
|
if (property.isAnnotationPresent(Indexed.class)) {
|
||||||
|
|
||||||
if (field.isAnnotationPresent(Indexed.class)) {
|
Indexed index = property.findAnnotation(Indexed.class);
|
||||||
|
|
||||||
Indexed index = field.getAnnotation(Indexed.class);
|
|
||||||
String name = index.name();
|
String name = index.name();
|
||||||
|
|
||||||
if (!StringUtils.hasText(name)) {
|
if (!StringUtils.hasText(name)) {
|
||||||
name = persistentProperty.getFieldName();
|
name = property.getFieldName();
|
||||||
} else {
|
} else {
|
||||||
if (!name.equals(field.getName()) && index.unique() && !index.sparse()) {
|
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.
|
// Names don't match, and sparse is not true. This situation will generate an error on the server.
|
||||||
if (log.isWarnEnabled()) {
|
if (LOGGER.isWarnEnabled()) {
|
||||||
log.warn("The index name " + name + " doesn't match this property name: " + field.getName()
|
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.");
|
+ ". Setting sparse=true on this index will prevent errors when inserting documents.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,29 +139,31 @@ public class MongoPersistentEntityIndexCreator implements
|
|||||||
|
|
||||||
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
||||||
int direction = index.direction() == IndexDirection.ASCENDING ? 1 : -1;
|
int direction = index.direction() == IndexDirection.ASCENDING ? 1 : -1;
|
||||||
DBObject definition = new BasicDBObject(persistentProperty.getFieldName(), direction);
|
DBObject definition = new BasicDBObject(property.getFieldName(), direction);
|
||||||
|
|
||||||
ensureIndex(collection, name, definition, index.unique(), index.dropDups(), index.sparse(),
|
ensureIndex(collection, name, definition, index.unique(), index.dropDups(), index.sparse(),
|
||||||
index.background(), index.expireAfterSeconds());
|
index.background(), index.expireAfterSeconds());
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
log.debug("Created property index " + index);
|
LOGGER.debug("Created property index " + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (field.isAnnotationPresent(GeoSpatialIndexed.class)) {
|
} else if (property.isAnnotationPresent(GeoSpatialIndexed.class)) {
|
||||||
|
|
||||||
GeoSpatialIndexed index = field.getAnnotation(GeoSpatialIndexed.class);
|
GeoSpatialIndexed index = property.findAnnotation(GeoSpatialIndexed.class);
|
||||||
|
|
||||||
GeospatialIndex indexObject = new GeospatialIndex(persistentProperty.getFieldName());
|
GeospatialIndex indexObject = new GeospatialIndex(property.getFieldName());
|
||||||
indexObject.withMin(index.min()).withMax(index.max());
|
indexObject.withMin(index.min()).withMax(index.max());
|
||||||
indexObject.named(StringUtils.hasText(index.name()) ? index.name() : field.getName());
|
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();
|
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
|
||||||
mongoDbFactory.getDb().getCollection(collection)
|
mongoDbFactory.getDb().getCollection(collection)
|
||||||
.ensureIndex(indexObject.getIndexKeys(), indexObject.getIndexOptions());
|
.ensureIndex(indexObject.getIndexKeys(), indexObject.getIndexOptions());
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
log.debug(String.format("Created %s for entity %s in collection %s! ", indexObject, entity.getType(),
|
LOGGER.debug(String.format("Created %s for entity %s in collection %s! ", indexObject, entity.getType(),
|
||||||
collection));
|
collection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.springframework.data.mapping.Association;
|
|||||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
@@ -50,17 +49,14 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
|
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
|
||||||
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
|
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
|
||||||
|
|
||||||
private static final Field CAUSE_FIELD;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
||||||
SUPPORTED_ID_TYPES.add(ObjectId.class);
|
SUPPORTED_ID_TYPES.add(ObjectId.class);
|
||||||
SUPPORTED_ID_TYPES.add(String.class);
|
SUPPORTED_ID_TYPES.add(String.class);
|
||||||
SUPPORTED_ID_TYPES.add(BigInteger.class);
|
SUPPORTED_ID_TYPES.add(BigInteger.class);
|
||||||
|
|
||||||
SUPPORTED_ID_PROPERTY_NAMES.add("id");
|
SUPPORTED_ID_PROPERTY_NAMES.add("id");
|
||||||
SUPPORTED_ID_PROPERTY_NAMES.add("_id");
|
SUPPORTED_ID_PROPERTY_NAMES.add("_id");
|
||||||
|
|
||||||
CAUSE_FIELD = ReflectionUtils.findField(Throwable.class, "cause");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FieldNamingStrategy fieldNamingStrategy;
|
private final FieldNamingStrategy fieldNamingStrategy;
|
||||||
@@ -86,14 +82,6 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mapping.FooBasicPersistentProperty#isAssociation()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isAssociation() {
|
|
||||||
return field.isAnnotationPresent(DBRef.class) || super.isAssociation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Also considers fields as id that are of supported id type and name.
|
* Also considers fields as id that are of supported id type and name.
|
||||||
*
|
*
|
||||||
@@ -108,7 +96,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
|
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
|
||||||
return SUPPORTED_ID_PROPERTY_NAMES.contains(field.getName());
|
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -163,8 +151,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder()
|
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder()
|
||||||
*/
|
*/
|
||||||
public int getFieldOrder() {
|
public int getFieldOrder() {
|
||||||
org.springframework.data.mongodb.core.mapping.Field annotation = getField().getAnnotation(
|
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class);
|
||||||
org.springframework.data.mongodb.core.mapping.Field.class);
|
|
||||||
return annotation != null ? annotation.order() : Integer.MAX_VALUE;
|
return annotation != null ? annotation.order() : Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +169,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isDbReference()
|
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isDbReference()
|
||||||
*/
|
*/
|
||||||
public boolean isDbReference() {
|
public boolean isDbReference() {
|
||||||
return getField().isAnnotationPresent(DBRef.class);
|
return isAnnotationPresent(DBRef.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,14 +177,6 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
|||||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getDBRef()
|
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getDBRef()
|
||||||
*/
|
*/
|
||||||
public DBRef getDBRef() {
|
public DBRef getDBRef() {
|
||||||
return getField().getAnnotation(DBRef.class);
|
return findAnnotation(DBRef.class);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess()
|
|
||||||
*/
|
|
||||||
public boolean usePropertyAccess() {
|
|
||||||
return CAUSE_FIELD.equals(getField());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 by the original author(s).
|
* Copyright 2011-2013 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.
|
||||||
@@ -27,7 +27,8 @@ import org.springframework.data.annotation.Reference;
|
|||||||
* An annotation that indicates the annotated field is to be stored using a {@link com.mongodb.DBRef}.
|
* An annotation that indicates the annotated field is to be stored using a {@link com.mongodb.DBRef}.
|
||||||
*
|
*
|
||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @authot Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@@ -41,4 +42,11 @@ public @interface DBRef {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String db() default "";
|
String db() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether the referenced entity should be loaded lazily. This defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean lazy() default false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 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.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.mapping.event;
|
package org.springframework.data.mongodb.core.mapping.event;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectFactory;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.data.auditing.AuditingHandler;
|
import org.springframework.data.auditing.AuditingHandler;
|
||||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||||
@@ -25,20 +26,22 @@ import org.springframework.util.Assert;
|
|||||||
* Event listener to populate auditing related fields on an entity about to be saved.
|
* Event listener to populate auditing related fields on an entity about to be saved.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class AuditingEventListener implements ApplicationListener<BeforeConvertEvent<Object>> {
|
public class AuditingEventListener implements ApplicationListener<BeforeConvertEvent<Object>> {
|
||||||
|
|
||||||
private final IsNewAwareAuditingHandler<Object> auditingHandler;
|
private final ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}.
|
* Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}
|
||||||
|
* provided by the given {@link ObjectFactory}.
|
||||||
*
|
*
|
||||||
* @param auditingHandler must not be {@literal null}.
|
* @param auditingHandlerFactory must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public AuditingEventListener(IsNewAwareAuditingHandler<Object> auditingHandler) {
|
public AuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory) {
|
||||||
|
|
||||||
Assert.notNull(auditingHandler, "IsNewAwareAuditingHandler must not be null!");
|
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
|
||||||
this.auditingHandler = auditingHandler;
|
this.auditingHandlerFactory = auditingHandlerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -48,6 +51,6 @@ public class AuditingEventListener implements ApplicationListener<BeforeConvertE
|
|||||||
public void onApplicationEvent(BeforeConvertEvent<Object> event) {
|
public void onApplicationEvent(BeforeConvertEvent<Object> event) {
|
||||||
|
|
||||||
Object entity = event.getSource();
|
Object entity = event.getSource();
|
||||||
auditingHandler.markAudited(entity);
|
auditingHandlerFactory.getObject().markAudited(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2012 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.
|
||||||
@@ -23,7 +23,7 @@ package org.springframework.data.mongodb.core.mapreduce;
|
|||||||
*/
|
*/
|
||||||
public class MapReduceCounts {
|
public class MapReduceCounts {
|
||||||
|
|
||||||
public static MapReduceCounts NONE = new MapReduceCounts(-1, -1, -1);
|
public static final MapReduceCounts NONE = new MapReduceCounts(-1, -1, -1);
|
||||||
|
|
||||||
private final long inputCount;
|
private final long inputCount;
|
||||||
private final long emitCount;
|
private final long emitCount;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011 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.
|
||||||
@@ -25,10 +25,11 @@ import java.util.List;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.bson.BSON;
|
import org.bson.BSON;
|
||||||
|
import org.springframework.data.geo.Circle;
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.geo.Shape;
|
||||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||||
import org.springframework.data.mongodb.core.geo.Circle;
|
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||||
import org.springframework.data.mongodb.core.geo.Point;
|
|
||||||
import org.springframework.data.mongodb.core.geo.Shape;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
@@ -39,6 +40,11 @@ import com.mongodb.DBObject;
|
|||||||
/**
|
/**
|
||||||
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
|
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
|
||||||
* criteria. Static import of the 'Criteria.where' method will improve readability.
|
* criteria. Static import of the 'Criteria.where' method will improve readability.
|
||||||
|
*
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class Criteria implements CriteriaDefinition {
|
public class Criteria implements CriteriaDefinition {
|
||||||
|
|
||||||
@@ -48,11 +54,8 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
private static final Object NOT_SET = new Object();
|
private static final Object NOT_SET = new Object();
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
|
|
||||||
private List<Criteria> criteriaChain;
|
private List<Criteria> criteriaChain;
|
||||||
|
|
||||||
private LinkedHashMap<String, Object> criteria = new LinkedHashMap<String, Object>();
|
private LinkedHashMap<String, Object> criteria = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
private Object isValue = NOT_SET;
|
private Object isValue = NOT_SET;
|
||||||
|
|
||||||
public Criteria() {
|
public Criteria() {
|
||||||
@@ -97,13 +100,16 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria is(Object o) {
|
public Criteria is(Object o) {
|
||||||
if (isValue != NOT_SET) {
|
|
||||||
|
if (!isValue.equals(NOT_SET)) {
|
||||||
throw new InvalidMongoDbApiUsageException(
|
throw new InvalidMongoDbApiUsageException(
|
||||||
"Multiple 'is' values declared. You need to use 'and' with multiple criteria");
|
"Multiple 'is' values declared. You need to use 'and' with multiple criteria");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastOperatorWasNot()) {
|
if (lastOperatorWasNot()) {
|
||||||
throw new InvalidMongoDbApiUsageException("Invalid query: 'not' can't be used with 'is' - use 'ne' instead.");
|
throw new InvalidMongoDbApiUsageException("Invalid query: 'not' can't be used with 'is' - use 'ne' instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isValue = o;
|
this.isValue = o;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -113,8 +119,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $ne operator
|
* Creates a criterion using the {@literal $ne} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/ne/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -124,8 +131,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $lt operator
|
* Creates a criterion using the {@literal $lt} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/lt/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -135,8 +143,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $lte operator
|
* Creates a criterion using the {@literal $lte} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/lte/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -146,8 +155,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $gt operator
|
* Creates a criterion using the {@literal $gt} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/gt/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -157,8 +167,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $gte operator
|
* Creates a criterion using the {@literal $gte} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/gte/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -168,8 +179,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $in operator
|
* Creates a criterion using the {@literal $in} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/in/
|
||||||
* @param o the values to match against
|
* @param o the values to match against
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -183,8 +195,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $in operator
|
* Creates a criterion using the {@literal $in} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/in/
|
||||||
* @param c the collection containing the values to match against
|
* @param c the collection containing the values to match against
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -194,8 +207,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $nin operator
|
* Creates a criterion using the {@literal $nin} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/nin/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -203,14 +217,22 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
return nin(Arrays.asList(o));
|
return nin(Arrays.asList(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a criterion using the {@literal $nin} operator.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/nin/
|
||||||
|
* @param o
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Criteria nin(Collection<?> o) {
|
public Criteria nin(Collection<?> o) {
|
||||||
criteria.put("$nin", o);
|
criteria.put("$nin", o);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $mod operator
|
* Creates a criterion using the {@literal $mod} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/mod/
|
||||||
* @param value
|
* @param value
|
||||||
* @param remainder
|
* @param remainder
|
||||||
* @return
|
* @return
|
||||||
@@ -224,8 +246,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $all operator
|
* Creates a criterion using the {@literal $all} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/all/
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -233,14 +256,22 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
return all(Arrays.asList(o));
|
return all(Arrays.asList(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a criterion using the {@literal $all} operator.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/all/
|
||||||
|
* @param o
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Criteria all(Collection<?> o) {
|
public Criteria all(Collection<?> o) {
|
||||||
criteria.put("$all", o);
|
criteria.put("$all", o);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $size operator
|
* Creates a criterion using the {@literal $size} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/size/
|
||||||
* @param s
|
* @param s
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -250,8 +281,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $exists operator
|
* Creates a criterion using the {@literal $exists} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/exists/
|
||||||
* @param b
|
* @param b
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -261,8 +293,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $type operator
|
* Creates a criterion using the {@literal $type} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/type/
|
||||||
* @param t
|
* @param t
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -272,22 +305,31 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $not meta operator which affects the clause directly following
|
* Creates a criterion using the {@literal $not} meta operator which affects the clause directly following
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/not/
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria not() {
|
public Criteria not() {
|
||||||
return not(null);
|
return not(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a criterion using the {@literal $not} operator.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/not/
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private Criteria not(Object value) {
|
private Criteria not(Object value) {
|
||||||
criteria.put("$not", value);
|
criteria.put("$not", value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using a $regex
|
* Creates a criterion using a {@literal $regex} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/regex/
|
||||||
* @param re
|
* @param re
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -296,8 +338,10 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using a $regex and $options
|
* Creates a criterion using a {@literal $regex} and {@literal $options} operator.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/regex/
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/regex/#op._S_options
|
||||||
* @param re
|
* @param re
|
||||||
* @param options
|
* @param options
|
||||||
* @return
|
* @return
|
||||||
@@ -330,51 +374,79 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a geospatial criterion using a $within $center operation. This is only available for Mongo 1.7 and higher.
|
* Creates a geospatial criterion using a {@literal $within $centerSphere} operation. This is only available for Mongo
|
||||||
|
* 1.7 and higher.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
|
||||||
* @param circle must not be {@literal null}
|
* @param circle must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria withinSphere(Circle circle) {
|
public Criteria withinSphere(Circle circle) {
|
||||||
Assert.notNull(circle);
|
Assert.notNull(circle);
|
||||||
criteria.put("$within", new BasicDBObject("$centerSphere", circle.asList()));
|
criteria.put("$within", new GeoCommand(new Sphere(circle)));
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Criteria within(Shape shape) {
|
|
||||||
|
|
||||||
Assert.notNull(shape);
|
|
||||||
criteria.put("$within", new BasicDBObject(shape.getCommand(), shape.asList()));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a geospatial criterion using a $near operation
|
* @see Criteria#withinSphere(Circle)
|
||||||
|
* @param circle
|
||||||
|
* @return
|
||||||
|
* @deprecated As of 1.5, Use {@link #withinSphere(Circle)}. This method is scheduled to be removed in the next major
|
||||||
|
* release.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public Criteria withinSphere(org.springframework.data.mongodb.core.geo.Circle circle) {
|
||||||
|
Assert.notNull(circle);
|
||||||
|
criteria.put("$within", new GeoCommand(new Sphere(circle)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a geospatial criterion using a {@literal $within} operation.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||||
|
* @param shape
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Criteria within(Shape shape) {
|
||||||
|
|
||||||
|
Assert.notNull(shape);
|
||||||
|
criteria.put("$within", new GeoCommand(shape));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a geospatial criterion using a {@literal $near} operation.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/near/
|
||||||
* @param point must not be {@literal null}
|
* @param point must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria near(Point point) {
|
public Criteria near(Point point) {
|
||||||
Assert.notNull(point);
|
Assert.notNull(point);
|
||||||
criteria.put("$near", point.asList());
|
criteria.put("$near", point);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a geospatial criterion using a $nearSphere operation. This is only available for Mongo 1.7 and higher.
|
* Creates a geospatial criterion using a {@literal $nearSphere} operation. This is only available for Mongo 1.7 and
|
||||||
|
* higher.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/nearSphere/
|
||||||
* @param point must not be {@literal null}
|
* @param point must not be {@literal null}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria nearSphere(Point point) {
|
public Criteria nearSphere(Point point) {
|
||||||
Assert.notNull(point);
|
Assert.notNull(point);
|
||||||
criteria.put("$nearSphere", point.asList());
|
criteria.put("$nearSphere", point);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a geospatical criterion using a $maxDistance operation, for use with $near
|
* Creates a geospatical criterion using a {@literal $maxDistance} operation, for use with $near
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/maxDistance/
|
||||||
* @param maxDistance
|
* @param maxDistance
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -384,8 +456,9 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a criterion using the $elemMatch operator
|
* Creates a criterion using the {@literal $elemMatch} operator
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/query/elemMatch/
|
||||||
* @param c
|
* @param c
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -396,34 +469,54 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an 'or' criteria using the $or operator for all of the provided criteria
|
* Creates an 'or' criteria using the $or operator for all of the provided criteria
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $or operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #orOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria orOperator(Criteria... criteria) {
|
public Criteria orOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$or").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$or").is(bsonList));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria
|
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria.
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $nor operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #norOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria norOperator(Criteria... criteria) {
|
public Criteria norOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$nor").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$nor").is(bsonList));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an 'and' criteria using the $and operator for all of the provided criteria
|
* Creates an 'and' criteria using the $and operator for all of the provided criteria.
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $and operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #andOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria andOperator(Criteria... criteria) {
|
public Criteria andOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$and").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Criteria registerCriteriaChainElement(Criteria criteria) {
|
||||||
|
|
||||||
|
if (lastOperatorWasNot()) {
|
||||||
|
throw new IllegalArgumentException("operator $not is not allowed around criteria chain element: "
|
||||||
|
+ criteria.getCriteriaObject());
|
||||||
|
} else {
|
||||||
|
criteriaChain.add(criteria);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,8 +544,10 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected DBObject getSingleCriteriaObject() {
|
protected DBObject getSingleCriteriaObject() {
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
boolean not = false;
|
boolean not = false;
|
||||||
|
|
||||||
for (String k : this.criteria.keySet()) {
|
for (String k : this.criteria.keySet()) {
|
||||||
Object value = this.criteria.get(k);
|
Object value = this.criteria.get(k);
|
||||||
if (not) {
|
if (not) {
|
||||||
@@ -468,13 +563,16 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject queryCriteria = new BasicDBObject();
|
DBObject queryCriteria = new BasicDBObject();
|
||||||
if (isValue != NOT_SET) {
|
|
||||||
|
if (!NOT_SET.equals(isValue)) {
|
||||||
queryCriteria.put(this.key, this.isValue);
|
queryCriteria.put(this.key, this.isValue);
|
||||||
queryCriteria.putAll(dbo);
|
queryCriteria.putAll(dbo);
|
||||||
} else {
|
} else {
|
||||||
queryCriteria.put(this.key, dbo);
|
queryCriteria.put(this.key, dbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryCriteria;
|
return queryCriteria;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.query;
|
||||||
|
|
||||||
|
import org.springframework.data.geo.Box;
|
||||||
|
import org.springframework.data.geo.Circle;
|
||||||
|
import org.springframework.data.geo.Polygon;
|
||||||
|
import org.springframework.data.geo.Shape;
|
||||||
|
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around a {@link Shape} to allow appropriate query rendering.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public class GeoCommand {
|
||||||
|
|
||||||
|
private final Shape shape;
|
||||||
|
private final String command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GeoCommand}.
|
||||||
|
*
|
||||||
|
* @param shape must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public GeoCommand(Shape shape) {
|
||||||
|
|
||||||
|
Assert.notNull(shape, "Shape must not be null!");
|
||||||
|
|
||||||
|
this.shape = shape;
|
||||||
|
this.command = getCommand(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the shape
|
||||||
|
*/
|
||||||
|
public Shape getShape() {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the command
|
||||||
|
*/
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MongoDB command for the given {@link Shape}.
|
||||||
|
*
|
||||||
|
* @param shape must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private String getCommand(Shape shape) {
|
||||||
|
|
||||||
|
Assert.notNull(shape, "Shape must not be null!");
|
||||||
|
|
||||||
|
if (shape instanceof Box) {
|
||||||
|
return org.springframework.data.mongodb.core.geo.Box.COMMAND;
|
||||||
|
} else if (shape instanceof Circle || shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
|
||||||
|
return org.springframework.data.mongodb.core.geo.Circle.COMMAND;
|
||||||
|
} else if (shape instanceof Polygon) {
|
||||||
|
return org.springframework.data.mongodb.core.geo.Polygon.COMMAND;
|
||||||
|
} else if (shape instanceof Sphere) {
|
||||||
|
return org.springframework.data.mongodb.core.geo.Sphere.COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unknown shape: " + shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2013 the original author or authors.
|
* Copyright 2011-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,11 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.query;
|
package org.springframework.data.mongodb.core.query;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.geo.CustomMetric;
|
import java.util.Arrays;
|
||||||
import org.springframework.data.mongodb.core.geo.Distance;
|
|
||||||
import org.springframework.data.mongodb.core.geo.Metric;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.mongodb.core.geo.Metrics;
|
import org.springframework.data.geo.CustomMetric;
|
||||||
import org.springframework.data.mongodb.core.geo.Point;
|
import org.springframework.data.geo.Distance;
|
||||||
|
import org.springframework.data.geo.Metric;
|
||||||
|
import org.springframework.data.geo.Metrics;
|
||||||
|
import org.springframework.data.geo.Point;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
@@ -29,8 +32,10 @@ import com.mongodb.DBObject;
|
|||||||
* Builder class to build near-queries.
|
* Builder class to build near-queries.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class NearQuery {
|
public final class NearQuery {
|
||||||
|
|
||||||
private final Point point;
|
private final Point point;
|
||||||
private Query query;
|
private Query query;
|
||||||
@@ -38,6 +43,7 @@ public class NearQuery {
|
|||||||
private Metric metric;
|
private Metric metric;
|
||||||
private boolean spherical;
|
private boolean spherical;
|
||||||
private Integer num;
|
private Integer num;
|
||||||
|
private Integer skip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link NearQuery}.
|
* Creates a new {@link NearQuery}.
|
||||||
@@ -116,7 +122,7 @@ public class NearQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the number of results to return.
|
* Configures the maximum number of results to return.
|
||||||
*
|
*
|
||||||
* @param num
|
* @param num
|
||||||
* @return
|
* @return
|
||||||
@@ -126,6 +132,31 @@ public class NearQuery {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the number of results to skip.
|
||||||
|
*
|
||||||
|
* @param skip
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public NearQuery skip(int skip) {
|
||||||
|
this.skip = skip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link Pageable} to use.
|
||||||
|
*
|
||||||
|
* @param pageable must not be {@literal null}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public NearQuery with(Pageable pageable) {
|
||||||
|
|
||||||
|
Assert.notNull(pageable, "Pageable must not be 'null'.");
|
||||||
|
this.num = pageable.getOffset() + pageable.getPageSize();
|
||||||
|
this.skip = pageable.getOffset();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the max distance results shall have from the configured origin. If a {@link Metric} was set before the given
|
* Sets the max distance results shall have from the configured origin. If a {@link Metric} was set before the given
|
||||||
* value will be interpreted as being a value in that metric. E.g.
|
* value will be interpreted as being a value in that metric. E.g.
|
||||||
@@ -285,19 +316,34 @@ public class NearQuery {
|
|||||||
/**
|
/**
|
||||||
* Adds an actual query to the {@link NearQuery} to restrict the objects considered for the actual near operation.
|
* Adds an actual query to the {@link NearQuery} to restrict the objects considered for the actual near operation.
|
||||||
*
|
*
|
||||||
* @param query
|
* @param query must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public NearQuery query(Query query) {
|
public NearQuery query(Query query) {
|
||||||
|
|
||||||
|
Assert.notNull(query, "Cannot apply 'null' query on NearQuery.");
|
||||||
this.query = query;
|
this.query = query;
|
||||||
|
this.skip = query.getSkip();
|
||||||
|
|
||||||
|
if (query.getLimit() != 0) {
|
||||||
|
this.num = query.getLimit();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of elements to skip.
|
||||||
|
*/
|
||||||
|
public Integer getSkip() {
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link DBObject} built by the {@link NearQuery}.
|
* Returns the {@link DBObject} built by the {@link NearQuery}.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public DBObject toDBObject() {
|
public DBObject toDBObject() {
|
||||||
|
|
||||||
BasicDBObject dbObject = new BasicDBObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
@@ -318,7 +364,8 @@ public class NearQuery {
|
|||||||
dbObject.put("num", num);
|
dbObject.put("num", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbObject.put("near", point.asList());
|
dbObject.put("near", Arrays.asList(point.getX(), point.getY()));
|
||||||
|
|
||||||
dbObject.put("spherical", spherical);
|
dbObject.put("spherical", spherical);
|
||||||
|
|
||||||
return dbObject;
|
return dbObject;
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -23,6 +23,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
@@ -41,10 +42,10 @@ import com.mongodb.DBObject;
|
|||||||
*/
|
*/
|
||||||
public class Query {
|
public class Query {
|
||||||
|
|
||||||
private final static String RESTRICTED_TYPES_KEY = "_$RESTRICTED_TYPES";
|
private static final String RESTRICTED_TYPES_KEY = "_$RESTRICTED_TYPES";
|
||||||
|
|
||||||
private final Set<Class<?>> restrictedTypes = new HashSet<Class<?>>();
|
private final Set<Class<?>> restrictedTypes = new HashSet<Class<?>>();
|
||||||
private LinkedHashMap<String, Criteria> criteria = new LinkedHashMap<String, Criteria>();
|
private final Map<String, Criteria> criteria = new LinkedHashMap<String, Criteria>();
|
||||||
private Field fieldSpec;
|
private Field fieldSpec;
|
||||||
private Sort sort;
|
private Sort sort;
|
||||||
private int skip;
|
private int skip;
|
||||||
@@ -98,11 +99,23 @@ public class Query {
|
|||||||
return this.fieldSpec;
|
return this.fieldSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set number of documents to skip before returning results.
|
||||||
|
*
|
||||||
|
* @param skip
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Query skip(int skip) {
|
public Query skip(int skip) {
|
||||||
this.skip = skip;
|
this.skip = skip;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit the number of returned documents to {@code limit}.
|
||||||
|
*
|
||||||
|
* @param limit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Query limit(int limit) {
|
public Query limit(int limit) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
return this;
|
return this;
|
||||||
@@ -197,6 +210,7 @@ public class Query {
|
|||||||
public DBObject getQueryObject() {
|
public DBObject getQueryObject() {
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
|
|
||||||
for (String k : criteria.keySet()) {
|
for (String k : criteria.keySet()) {
|
||||||
CriteriaDefinition c = criteria.get(k);
|
CriteriaDefinition c = criteria.get(k);
|
||||||
DBObject cl = c.getCriteriaObject();
|
DBObject cl = c.getCriteriaObject();
|
||||||
@@ -211,37 +225,45 @@ public class Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DBObject getFieldsObject() {
|
public DBObject getFieldsObject() {
|
||||||
if (this.fieldSpec == null) {
|
return this.fieldSpec == null ? null : fieldSpec.getFieldsObject();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return fieldSpec.getFieldsObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DBObject getSortObject() {
|
public DBObject getSortObject() {
|
||||||
|
|
||||||
if (this.sort == null && this.sort == null) {
|
if (this.sort == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
|
|
||||||
if (this.sort != null) {
|
for (org.springframework.data.domain.Sort.Order order : this.sort) {
|
||||||
for (org.springframework.data.domain.Sort.Order order : this.sort) {
|
dbo.put(order.getProperty(), order.isAscending() ? 1 : -1);
|
||||||
dbo.put(order.getProperty(), order.isAscending() ? 1 : -1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of documents to skip.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int getSkip() {
|
public int getSkip() {
|
||||||
return this.skip;
|
return this.skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum number of documents to be return.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int getLimit() {
|
public int getLimit() {
|
||||||
return this.limit;
|
return this.limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String getHint() {
|
public String getHint() {
|
||||||
return hint;
|
return hint;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -16,11 +16,18 @@
|
|||||||
package org.springframework.data.mongodb.core.query;
|
package org.springframework.data.mongodb.core.query;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
|
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;
|
||||||
@@ -31,6 +38,8 @@ import com.mongodb.DBObject;
|
|||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Becca Gaspard
|
||||||
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class Update {
|
public class Update {
|
||||||
|
|
||||||
@@ -38,7 +47,9 @@ public class Update {
|
|||||||
LAST, FIRST
|
LAST, FIRST
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, Object> modifierOps = new LinkedHashMap<String, Object>();
|
private Set<String> keysToUpdate = new HashSet<String>();
|
||||||
|
private Map<String, Object> modifierOps = new LinkedHashMap<String, Object>();
|
||||||
|
private Map<String, PushOperatorBuilder> pushCommandBuilders = new LinkedHashMap<String, PushOperatorBuilder>(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static factory method to create an Update using the provided key
|
* Static factory method to create an Update using the provided key
|
||||||
@@ -72,15 +83,22 @@ public class Update {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
update.modifierOps.put(key, object.get(key));
|
Object value = object.get(key);
|
||||||
|
update.modifierOps.put(key, value);
|
||||||
|
if (isKeyword(key) && value instanceof DBObject) {
|
||||||
|
update.keysToUpdate.addAll(((DBObject) value).keySet());
|
||||||
|
} else {
|
||||||
|
update.keysToUpdate.add(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return update;
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $set update modifier
|
* Update using the {@literal $set} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/set/
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
@@ -91,8 +109,22 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $unset update modifier
|
* Update using the {@literal $setOnInsert} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/setOnInsert/
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Update setOnInsert(String key, Object value) {
|
||||||
|
addMultiFieldOperation("$setOnInsert", key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update using the {@literal $unset} update modifier
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/unset/
|
||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -102,8 +134,9 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $inc update modifier
|
* Update using the {@literal $inc} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/inc/
|
||||||
* @param key
|
* @param key
|
||||||
* @param inc
|
* @param inc
|
||||||
* @return
|
* @return
|
||||||
@@ -114,8 +147,9 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $push update modifier
|
* Update using the {@literal $push} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/push/
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
@@ -126,27 +160,59 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pushAll update modifier
|
* Update using {@code $push} modifier. <br/>
|
||||||
|
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values.
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/push/
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/each/
|
||||||
|
* @param key
|
||||||
|
* @return {@link PushOperatorBuilder} for given key
|
||||||
|
*/
|
||||||
|
public PushOperatorBuilder push(String key) {
|
||||||
|
|
||||||
|
if (!pushCommandBuilders.containsKey(key)) {
|
||||||
|
pushCommandBuilders.put(key, new PushOperatorBuilder(key));
|
||||||
|
}
|
||||||
|
return pushCommandBuilders.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update using the {@code $pushAll} update modifier. <br>
|
||||||
|
* <b>Note</b>: In mongodb 2.4 the usage of {@code $pushAll} has been deprecated in favor of {@code $push $each}.
|
||||||
|
* {@link #push(String)}) returns a builder that can be used to populate the {@code $each} object.
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/pushAll/
|
||||||
* @param key
|
* @param key
|
||||||
* @param values
|
* @param values
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pushAll(String key, Object[] values) {
|
public Update pushAll(String key, Object[] values) {
|
||||||
|
|
||||||
Object[] convertedValues = new Object[values.length];
|
Object[] convertedValues = new Object[values.length];
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
convertedValues[i] = values[i];
|
convertedValues[i] = values[i];
|
||||||
}
|
}
|
||||||
DBObject keyValue = new BasicDBObject();
|
addMultiFieldOperation("$pushAll", key, convertedValues);
|
||||||
keyValue.put(key, convertedValues);
|
|
||||||
modifierOps.put("$pushAll", keyValue);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $addToSet update modifier
|
* Update using {@code $addToSet} modifier. <br/>
|
||||||
|
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
|
* @return
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public AddToSetBuilder addToSet(String key) {
|
||||||
|
return new AddToSetBuilder(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update using the {@literal $addToSet} update modifier
|
||||||
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/addToSet/
|
||||||
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -156,8 +222,9 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pop update modifier
|
* Update using the {@literal $pop} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/pop/
|
||||||
* @param key
|
* @param key
|
||||||
* @param pos
|
* @param pos
|
||||||
* @return
|
* @return
|
||||||
@@ -168,8 +235,9 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pull update modifier
|
* Update using the {@literal $pull} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/pull/
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
@@ -180,26 +248,27 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pullAll update modifier
|
* Update using the {@literal $pullAll} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/pullAll/
|
||||||
* @param key
|
* @param key
|
||||||
* @param values
|
* @param values
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pullAll(String key, Object[] values) {
|
public Update pullAll(String key, Object[] values) {
|
||||||
|
|
||||||
Object[] convertedValues = new Object[values.length];
|
Object[] convertedValues = new Object[values.length];
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
convertedValues[i] = values[i];
|
convertedValues[i] = values[i];
|
||||||
}
|
}
|
||||||
DBObject keyValue = new BasicDBObject();
|
addFieldOperation("$pullAll", key, convertedValues);
|
||||||
keyValue.put(key, convertedValues);
|
|
||||||
modifierOps.put("$pullAll", keyValue);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $rename update modifier
|
* Update using the {@literal $rename} update modifier
|
||||||
*
|
*
|
||||||
|
* @see http://docs.mongodb.org/manual/reference/operator/update/rename/
|
||||||
* @param oldName
|
* @param oldName
|
||||||
* @param newName
|
* @param newName
|
||||||
* @return
|
* @return
|
||||||
@@ -217,8 +286,16 @@ public class Update {
|
|||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addFieldOperation(String operator, String key, Object value) {
|
||||||
|
|
||||||
|
Assert.hasText(key, "Key/Path for update must not be null or blank.");
|
||||||
|
modifierOps.put(operator, new BasicDBObject(key, value));
|
||||||
|
this.keysToUpdate.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
protected void addMultiFieldOperation(String operator, String key, Object value) {
|
protected void addMultiFieldOperation(String operator, String key, Object value) {
|
||||||
|
|
||||||
|
Assert.hasText(key, "Key/Path for update must not be null or blank.");
|
||||||
Object existingValue = this.modifierOps.get(operator);
|
Object existingValue = this.modifierOps.get(operator);
|
||||||
DBObject keyValueMap;
|
DBObject keyValueMap;
|
||||||
|
|
||||||
@@ -235,5 +312,183 @@ public class Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyValueMap.put(key, value);
|
keyValueMap.put(key, value);
|
||||||
|
this.keysToUpdate.add(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given {@code key} will be touched on execution.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean modifies(String key) {
|
||||||
|
return this.keysToUpdate.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspects given {@code key} for '$'.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean isKeyword(String key) {
|
||||||
|
return StringUtils.startsWithIgnoreCase(key, "$");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifiers holds a distinct collection of {@link Modifier}
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
|
public static class Modifiers {
|
||||||
|
|
||||||
|
private HashMap<String, Modifier> modifiers;
|
||||||
|
|
||||||
|
public Modifiers() {
|
||||||
|
this.modifiers = new LinkedHashMap<String, Modifier>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Modifier> getModifiers() {
|
||||||
|
return Collections.unmodifiableCollection(this.modifiers.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addModifier(Modifier modifier) {
|
||||||
|
this.modifiers.put(modifier.getKey(), modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface of nested commands.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
|
public static interface Modifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the command to send eg. {@code $push}
|
||||||
|
*/
|
||||||
|
String getKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return value to be sent with command
|
||||||
|
*/
|
||||||
|
Object getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link Modifier} representing {@code $each}.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
|
private static class Each implements Modifier {
|
||||||
|
|
||||||
|
private Object[] values;
|
||||||
|
|
||||||
|
public Each(Object... values) {
|
||||||
|
this.values = extractValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] extractValues(Object[] values) {
|
||||||
|
|
||||||
|
if (values == null || values.length == 0) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.length == 1 && values[0] instanceof Collection) {
|
||||||
|
return ((Collection<?>) values[0]).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] convertedValues = new Object[values.length];
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
convertedValues[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertedValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return "$each";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue() {
|
||||||
|
return this.values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for creating {@code $push} modifiers
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
*/
|
||||||
|
public class PushOperatorBuilder {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
private final Modifiers modifiers;
|
||||||
|
|
||||||
|
PushOperatorBuilder(String key) {
|
||||||
|
this.key = key;
|
||||||
|
this.modifiers = new Modifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propagates {@code $each} to {@code $push}
|
||||||
|
*
|
||||||
|
* @param values
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Update each(Object... values) {
|
||||||
|
|
||||||
|
this.modifiers.addModifier(new Each(values));
|
||||||
|
return Update.this.push(key, this.modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propagates {@link #value(Object)} to {@code $push}
|
||||||
|
*
|
||||||
|
* @param values
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Update value(Object value) {
|
||||||
|
return Update.this.push(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for creating {@code $addToSet} modifier.
|
||||||
|
*
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public class AddToSetBuilder {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
public AddToSetBuilder(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propagates {@code $each} to {@code $addToSet}
|
||||||
|
*
|
||||||
|
* @param values
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Update each(Object... values) {
|
||||||
|
return Update.this.addToSet(this.key, new Each(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propagates {@link #value(Object)} to {@code $addToSet}
|
||||||
|
*
|
||||||
|
* @param values
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Update value(Object value) {
|
||||||
|
return Update.this.addToSet(this.key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
import org.springframework.expression.spel.SpelNode;
|
||||||
|
import org.springframework.expression.spel.ast.Literal;
|
||||||
|
import org.springframework.expression.spel.ast.MethodReference;
|
||||||
|
import org.springframework.expression.spel.ast.Operator;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value object for nodes in an expression. Allows iterating ove potentially available child {@link ExpressionNode}s.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||||
|
|
||||||
|
private static final Iterator<ExpressionNode> EMPTY_ITERATOR = Collections.<ExpressionNode> emptySet().iterator();
|
||||||
|
|
||||||
|
private final SpelNode node;
|
||||||
|
private final ExpressionState state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionNode} from the given {@link SpelNode} and {@link ExpressionState}.
|
||||||
|
*
|
||||||
|
* @param node must not be {@literal null}.
|
||||||
|
* @param state must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
protected ExpressionNode(SpelNode node, ExpressionState state) {
|
||||||
|
|
||||||
|
Assert.notNull(node, "SpelNode must not be null!");
|
||||||
|
Assert.notNull(state, "ExpressionState must not be null!");
|
||||||
|
|
||||||
|
this.node = node;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to create {@link ExpressionNode}'s according to the given {@link SpelNode} and
|
||||||
|
* {@link ExpressionState}.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @param state must not be {@literal null}.
|
||||||
|
* @return an {@link ExpressionNode} for the given {@link SpelNode} or {@literal null} if {@literal null} was given
|
||||||
|
* for the {@link SpelNode}.
|
||||||
|
*/
|
||||||
|
public static ExpressionNode from(SpelNode node, ExpressionState state) {
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node instanceof Operator) {
|
||||||
|
return new OperatorNode((Operator) node, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node instanceof MethodReference) {
|
||||||
|
return new MethodReferenceNode((MethodReference) node, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node instanceof Literal) {
|
||||||
|
return new LiteralNode((Literal) node, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ExpressionNode(node, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the {@link ExpressionNode}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return node.toStringAST();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current {@link ExpressionNode} is backed by the given type.
|
||||||
|
*
|
||||||
|
* @param type must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isOfType(Class<?> type) {
|
||||||
|
|
||||||
|
Assert.notNull(type, "Type must not be empty!");
|
||||||
|
return type.isAssignableFrom(node.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given {@link ExpressionNode} is representing the same backing node type as the current one.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean isOfSameTypeAs(ExpressionNode node) {
|
||||||
|
return node == null ? false : this.node.getClass().equals(node.node.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExpressionNode} is a mathematical operation.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isMathematicalOperation() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExpressionNode} is a literal.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isLiteral() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the current node.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getValue() {
|
||||||
|
return node.getValue(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current node has child nodes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasChildren() {
|
||||||
|
return node.getChildCount() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the child {@link ExpressionNode} with the given index.
|
||||||
|
*
|
||||||
|
* @param index must not be negative.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ExpressionNode getChild(int index) {
|
||||||
|
|
||||||
|
Assert.isTrue(index >= 0);
|
||||||
|
return from(node.getChild(index), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link ExpressionNode} has a first child node that is not of the given type.
|
||||||
|
*
|
||||||
|
* @param type must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasfirstChildNotOfType(Class<?> type) {
|
||||||
|
|
||||||
|
Assert.notNull(type, "Type must not be null!");
|
||||||
|
return hasChildren() && !node.getChild(0).getClass().equals(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionNode} from the given {@link SpelNode}.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected ExpressionNode from(SpelNode node) {
|
||||||
|
return from(node, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Iterable#iterator()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterator<ExpressionNode> iterator() {
|
||||||
|
|
||||||
|
if (!hasChildren()) {
|
||||||
|
return EMPTY_ITERATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Iterator<ExpressionNode>() {
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return index < node.getChildCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExpressionNode next() {
|
||||||
|
return from(node.getChild(index++));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The context for an {@link ExpressionNode} transformation.
|
||||||
|
*
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class ExpressionTransformationContextSupport<T extends ExpressionNode> {
|
||||||
|
|
||||||
|
private final T currentNode;
|
||||||
|
private final ExpressionNode parentNode;
|
||||||
|
private final DBObject previousOperationObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ExpressionTransformationContextSupport} for the given {@link ExpressionNode}s and an optional
|
||||||
|
* previous operation.
|
||||||
|
*
|
||||||
|
* @param currentNode must not be {@literal null}.
|
||||||
|
* @param parentNode
|
||||||
|
* @param previousOperationObject
|
||||||
|
*/
|
||||||
|
public ExpressionTransformationContextSupport(T currentNode, ExpressionNode parentNode,
|
||||||
|
DBObject previousOperationObject) {
|
||||||
|
|
||||||
|
Assert.notNull(currentNode, "currentNode must not be null!");
|
||||||
|
|
||||||
|
this.currentNode = currentNode;
|
||||||
|
this.parentNode = parentNode;
|
||||||
|
this.previousOperationObject = previousOperationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current {@link ExpressionNode}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public T getCurrentNode() {
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent {@link ExpressionNode} or {@literal null} if none available.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ExpressionNode getParentNode() {
|
||||||
|
return parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the previously accumulated operaton object or {@literal null} if none available. Rather than manually
|
||||||
|
* adding stuff to the object prefer using {@link #addToPreviousOrReturn(Object)} to transparently do if one is
|
||||||
|
* present.
|
||||||
|
*
|
||||||
|
* @see #hasPreviousOperation()
|
||||||
|
* @see #addToPreviousOrReturn(Object)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DBObject getPreviousOperationObject() {
|
||||||
|
return previousOperationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a previous operation is present.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasPreviousOperation() {
|
||||||
|
return getPreviousOperationObject() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the parent node is of the same operation as the current node.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean parentIsSameOperation() {
|
||||||
|
return parentNode == null ? false : currentNode.isOfSameTypeAs(parentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given value to the previous operation and returns it.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DBObject addToPreviousOperation(Object value) {
|
||||||
|
extractArgumentListFrom(previousOperationObject).add(value);
|
||||||
|
return previousOperationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given value to the previous operation if one is present or returns the value to add as is.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object addToPreviousOrReturn(Object value) {
|
||||||
|
return hasPreviousOperation() ? addToPreviousOperation(value) : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasicDBList extractArgumentListFrom(DBObject context) {
|
||||||
|
return (BasicDBList) context.get(context.keySet().iterator().next());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI interface to implement components that can transfrom an {@link ExpressionTransformationContextSupport} into an
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public interface ExpressionTransformer<T extends ExpressionTransformationContextSupport<?>> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the given {@link ExpressionTransformationContextSupport} into an Object.
|
||||||
|
*
|
||||||
|
* @param context will never be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object transform(T context);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
import org.springframework.expression.spel.ast.FloatLiteral;
|
||||||
|
import org.springframework.expression.spel.ast.IntLiteral;
|
||||||
|
import org.springframework.expression.spel.ast.Literal;
|
||||||
|
import org.springframework.expression.spel.ast.LongLiteral;
|
||||||
|
import org.springframework.expression.spel.ast.NullLiteral;
|
||||||
|
import org.springframework.expression.spel.ast.RealLiteral;
|
||||||
|
import org.springframework.expression.spel.ast.StringLiteral;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a literal in an expression.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class LiteralNode extends ExpressionNode {
|
||||||
|
|
||||||
|
private final Literal literal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link LiteralNode} from the given {@link Literal} and {@link ExpressionState}.
|
||||||
|
*
|
||||||
|
* @param node must not be {@literal null}.
|
||||||
|
* @param state must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
LiteralNode(Literal node, ExpressionState state) {
|
||||||
|
super(node, state);
|
||||||
|
this.literal = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given {@link ExpressionNode} is a unary minus.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isUnaryMinus(ExpressionNode parent) {
|
||||||
|
|
||||||
|
if (!(parent instanceof OperatorNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperatorNode operator = (OperatorNode) parent;
|
||||||
|
return operator.isUnaryMinus() && operator.getRight() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.spel.ExpressionNode#isLiteral()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isLiteral() {
|
||||||
|
return literal instanceof FloatLiteral || literal instanceof RealLiteral || literal instanceof IntLiteral
|
||||||
|
|| literal instanceof LongLiteral || literal instanceof StringLiteral || literal instanceof NullLiteral;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
import org.springframework.expression.spel.ast.MethodReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ExpressionNode} representing a method reference.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public class MethodReferenceNode extends ExpressionNode {
|
||||||
|
|
||||||
|
private static final Map<String, String> FUNCTIONS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
|
||||||
|
map.put("concat", "$concat"); // Concatenates two strings.
|
||||||
|
map.put("strcasecmp", "$strcasecmp"); // Compares two strings and returns an integer that reflects the comparison.
|
||||||
|
map.put("substr", "$substr"); // Takes a string and returns portion of that string.
|
||||||
|
map.put("toLower", "$toLower"); // Converts a string to lowercase.
|
||||||
|
map.put("toUpper", "$toUpper"); // Converts a string to uppercase.
|
||||||
|
|
||||||
|
map.put("dayOfYear", "$dayOfYear"); // Converts a date to a number between 1 and 366.
|
||||||
|
map.put("dayOfMonth", "$dayOfMonth"); // Converts a date to a number between 1 and 31.
|
||||||
|
map.put("dayOfWeek", "$dayOfWeek"); // Converts a date to a number between 1 and 7.
|
||||||
|
map.put("year", "$year"); // Converts a date to the full year.
|
||||||
|
map.put("month", "$month"); // Converts a date into a number between 1 and 12.
|
||||||
|
map.put("week", "$week"); // Converts a date into a number between 0 and 53
|
||||||
|
map.put("hour", "$hour"); // Converts a date into a number between 0 and 23.
|
||||||
|
map.put("minute", "$minute"); // Converts a date into a number between 0 and 59.
|
||||||
|
map.put("second", "$second"); // Converts a date into a number between 0 and 59. May be 60 to account for leap
|
||||||
|
// seconds.
|
||||||
|
map.put("millisecond", "$millisecond"); // Returns the millisecond portion of a date as an integer between 0 and
|
||||||
|
|
||||||
|
FUNCTIONS = Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodReferenceNode(MethodReference reference, ExpressionState state) {
|
||||||
|
super(reference, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the method.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getMethodName() {
|
||||||
|
|
||||||
|
String name = getName();
|
||||||
|
String methodName = name.substring(0, name.indexOf('('));
|
||||||
|
return FUNCTIONS.get(methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 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.spel;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
import org.springframework.expression.spel.ast.OpDivide;
|
||||||
|
import org.springframework.expression.spel.ast.OpMinus;
|
||||||
|
import org.springframework.expression.spel.ast.OpModulus;
|
||||||
|
import org.springframework.expression.spel.ast.OpMultiply;
|
||||||
|
import org.springframework.expression.spel.ast.OpPlus;
|
||||||
|
import org.springframework.expression.spel.ast.Operator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ExpressionNode} representing an operator.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
|
public class OperatorNode extends ExpressionNode {
|
||||||
|
|
||||||
|
private static final Map<String, String> OPERATORS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
Map<String, String> map = new HashMap<String, String>(6);
|
||||||
|
|
||||||
|
map.put("+", "$add");
|
||||||
|
map.put("-", "$subtract");
|
||||||
|
map.put("*", "$multiply");
|
||||||
|
map.put("/", "$divide");
|
||||||
|
map.put("%", "$mod");
|
||||||
|
|
||||||
|
OPERATORS = Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Operator operator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link OperatorNode} from the given {@link Operator} and {@link ExpressionState}.
|
||||||
|
*
|
||||||
|
* @param node must not be {@literal null}.
|
||||||
|
* @param state must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
OperatorNode(Operator node, ExpressionState state) {
|
||||||
|
super(node, state);
|
||||||
|
this.operator = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.core.spel.ExpressionNode#isMathematicalOperation()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isMathematicalOperation() {
|
||||||
|
return operator instanceof OpMinus || operator instanceof OpPlus || operator instanceof OpMultiply
|
||||||
|
|| operator instanceof OpDivide || operator instanceof OpModulus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the operator is unary.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isUnaryOperator() {
|
||||||
|
return operator.getRightOperand() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Mongo expression of the operator.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getMongoOperator() {
|
||||||
|
return OPERATORS.get(operator.getOperatorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the operator is a unary minus, e.g. -1.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isUnaryMinus() {
|
||||||
|
return isUnaryOperator() && operator instanceof OpMinus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the left operand as {@link ExpressionNode}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ExpressionNode getLeft() {
|
||||||
|
return from(operator.getLeftOperand());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the right operand as {@link ExpressionNode}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ExpressionNode getRight() {
|
||||||
|
return from(operator.getRightOperand());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support classes to transform SpEL expressions into MongoDB expressions.
|
||||||
|
* @since 1.4
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.spel;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -31,6 +31,8 @@ import com.mongodb.gridfs.GridFSFile;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Martin Baumgartner
|
||||||
*/
|
*/
|
||||||
public interface GridFsOperations extends ResourcePatternResolver {
|
public interface GridFsOperations extends ResourcePatternResolver {
|
||||||
|
|
||||||
@@ -43,6 +45,24 @@ public interface GridFsOperations extends ResourcePatternResolver {
|
|||||||
*/
|
*/
|
||||||
GridFSFile store(InputStream content, String filename);
|
GridFSFile store(InputStream content, String filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given content into a file with the given name.
|
||||||
|
*
|
||||||
|
* @param content must not be {@literal null}.
|
||||||
|
* @param metadata can be {@literal null}.
|
||||||
|
* @return the {@link GridFSFile} just created
|
||||||
|
*/
|
||||||
|
GridFSFile store(InputStream content, Object metadata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given content into a file with the given name.
|
||||||
|
*
|
||||||
|
* @param content must not be {@literal null}.
|
||||||
|
* @param metadata can be {@literal null}.
|
||||||
|
* @return the {@link GridFSFile} just created
|
||||||
|
*/
|
||||||
|
GridFSFile store(InputStream content, DBObject metadata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given content into a file with the given name and content type.
|
* Stores the given content into a file with the given name and content type.
|
||||||
*
|
*
|
||||||
@@ -126,7 +146,7 @@ public interface GridFsOperations extends ResourcePatternResolver {
|
|||||||
* Returns all {@link GridFsResource} with the given file name.
|
* Returns all {@link GridFsResource} with the given file name.
|
||||||
*
|
*
|
||||||
* @param filename
|
* @param filename
|
||||||
* @return
|
* @return the resource if it exists or {@literal null}.
|
||||||
* @see ResourcePatternResolver#getResource(String)
|
* @see ResourcePatternResolver#getResource(String)
|
||||||
*/
|
*/
|
||||||
GridFsResource getResource(String filename);
|
GridFsResource getResource(String filename);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-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.
|
||||||
@@ -43,6 +43,8 @@ import com.mongodb.gridfs.GridFSInputFile;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Philipp Schneider
|
* @author Philipp Schneider
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Martin Baumgartner
|
||||||
*/
|
*/
|
||||||
public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver {
|
public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver {
|
||||||
|
|
||||||
@@ -88,6 +90,25 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
return store(content, filename, (Object) null);
|
return store(content, filename, (Object) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.Object)
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GridFSFile store(InputStream content, Object metadata) {
|
||||||
|
return store(content, null, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, com.mongodb.DBObject)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GridFSFile store(InputStream content, DBObject metadata) {
|
||||||
|
return store(content, null, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.String)
|
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.String)
|
||||||
@@ -101,7 +122,6 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.Object)
|
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#store(java.io.InputStream, java.lang.String, java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public GridFSFile store(InputStream content, String filename, Object metadata) {
|
public GridFSFile store(InputStream content, String filename, Object metadata) {
|
||||||
|
|
||||||
return store(content, filename, null, metadata);
|
return store(content, filename, null, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,10 +156,12 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
public GridFSFile store(InputStream content, String filename, String contentType, DBObject metadata) {
|
public GridFSFile store(InputStream content, String filename, String contentType, DBObject metadata) {
|
||||||
|
|
||||||
Assert.notNull(content);
|
Assert.notNull(content);
|
||||||
Assert.hasText(filename);
|
|
||||||
|
|
||||||
GridFSInputFile file = getGridFs().createFile(content);
|
GridFSInputFile file = getGridFs().createFile(content);
|
||||||
file.setFilename(filename);
|
|
||||||
|
if (filename != null) {
|
||||||
|
file.setFilename(filename);
|
||||||
|
}
|
||||||
|
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
file.setMetaData(metadata);
|
file.setMetaData(metadata);
|
||||||
@@ -158,7 +180,15 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#find(com.mongodb.DBObject)
|
* @see org.springframework.data.mongodb.gridfs.GridFsOperations#find(com.mongodb.DBObject)
|
||||||
*/
|
*/
|
||||||
public List<GridFSDBFile> find(Query query) {
|
public List<GridFSDBFile> find(Query query) {
|
||||||
return getGridFs().find(getMappedQuery(query));
|
|
||||||
|
if (query == null) {
|
||||||
|
return getGridFs().find((DBObject) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBObject queryObject = getMappedQuery(query.getQueryObject());
|
||||||
|
DBObject sortObject = getMappedQuery(query.getSortObject());
|
||||||
|
|
||||||
|
return getGridFs().find(queryObject, sortObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,7 +220,9 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
* @see org.springframework.core.io.ResourceLoader#getResource(java.lang.String)
|
* @see org.springframework.core.io.ResourceLoader#getResource(java.lang.String)
|
||||||
*/
|
*/
|
||||||
public GridFsResource getResource(String location) {
|
public GridFsResource getResource(String location) {
|
||||||
return new GridFsResource(findOne(query(whereFilename().is(location))));
|
|
||||||
|
GridFSDBFile file = findOne(query(whereFilename().is(location)));
|
||||||
|
return file != null ? new GridFsResource(file) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -221,7 +253,11 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DBObject getMappedQuery(Query query) {
|
private DBObject getMappedQuery(Query query) {
|
||||||
return query == null ? null : queryMapper.getMappedObject(query.getQueryObject(), null);
|
return query == null ? new Query().getQueryObject() : getMappedQuery(query.getQueryObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DBObject getMappedQuery(DBObject query) {
|
||||||
|
return query == null ? null : queryMapper.getMappedObject(query, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GridFS getGridFs() {
|
private GridFS getGridFs() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2013 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.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user