Compare commits

..

52 Commits

Author SHA1 Message Date
Spring Buildmaster
3001e2941f DATAMONGO-541 - Release 1.1.0.RELEASE. 2012-10-10 05:30:15 -07:00
Oliver Gierke
9cf72fbdd4 DATAMONGO-541 - Polished pom.xml for Maven central propagation. 2012-10-10 14:23:11 +02:00
Oliver Gierke
cb5144de0f DATAMONGO-541 - Updated reference docs and changelog. 2012-10-10 14:04:43 +02:00
Oliver Gierke
4be90e51ae DATAMONGO-541 - Upgrade to Spring Data Commons 1.4.0.RELEASE. 2012-10-10 14:04:27 +02:00
Oliver Gierke
6c368d557b DATAMONGO-548 - Upgrade to Querydsl 2.8.0. 2012-10-09 09:11:27 +02:00
Oliver Gierke
a8432e13a1 DATAMONGO-543 - Polished quick start section.
Updated dependency versions to Spring Data MongoDB and Spring. Removed explicit dependency listing. Removed section on how to migrate between 1.0 milestones. Removed obsolete paragraphs.
2012-09-20 10:38:46 +02:00
Oliver Gierke
05ac139554 DATAMONGO-528 - Documented GridFs support. 2012-09-17 15:04:19 +02:00
Oliver Gierke
3661b2981e DATAMONGO-456 - Fixed <db-factory /> element documentation in XSD. 2012-09-17 12:22:48 +02:00
Oliver Gierke
69bd7acf74 DATAMONGO-457 - Fixed links in reference documentation. 2012-09-17 12:07:52 +02:00
Oliver Gierke
d882af257f DATAMONGO-539 - Fixed MongoTemplate.remove(object, collectionName).
If the entity being removed using MongoTemplate.remove(object, collectionName) contained an id that could be converted into an ObjectID it wasn't removed correctly currently. This was caused by the fact that the intermediate call didn't hand over the entity type and thus the id conversion failed. This in turn caused the query not to match the previous saved object.
2012-09-17 11:57:09 +02:00
Oliver Gierke
c92058a79a DATAMONGO-539 - Added test case to show removing entity from explicit collection works. 2012-09-13 17:12:50 +02:00
Oliver Gierke
ed2b576261 DATAMONGO-538 - Query API can now work with Sort and Pageable from Spring Data Commons.
Introduced with(Sort sort) and with(Pageable pageable) on Query. Deprecated sort() method and the custom Sort class. Deprecated QueryUtils.applyPagination(…) and ….applySorting(…) and changed internal calls to this to use the Query API directly. Some JavaDoc polishing.
2012-09-13 10:54:23 +02:00
Oliver Gierke
6744446a48 DATAMONGO-532 - Synchronize DB authentication.
In multithreaded environments Mongo database authentication can be triggered twice if two or more threads refer to the same db instance. This is now prevented by synchronizing calls to db.authenticate(…).
2012-09-12 12:58:31 +02:00
Oliver Gierke
fdecec48b2 DATAMONGO-484 - Upgraded to MongoDB driver 2.9.1. 2012-09-12 11:54:20 +02:00
Oliver Gierke
f1289c46e6 DATAMONGO-535 - Fixed broken MongoDBUtils resource synchronization.
We now make sure we really re-use the database instance bound to the thread avoiding duplicate lookups of Mongo.getDb(…). This doesn't seem to gain a big performance benefit anymore as the Mongo instance caches the DB instances internally anyway.
2012-09-11 20:44:33 +02:00
Oliver Gierke
aa0b87be57 DATAMONGO-536 - Fixed package cycle introduced by SerializationUtils. 2012-09-11 20:44:32 +02:00
noter
2040f02d07 DATAMONGO-279 - Added support for optimistic locking.
Introduced @Version annotation to demarcate a version property on an entity. MongoTemplate will initialize this property on the first save of an instance if not set already. If it is already set, the template will bump the version number on subsequent saves and actually trigger an update backed by a query including the old version number. A failure to update the entity accordingly will then trigger an OptimisticLockingFailureException.

General JavaDoc polish in mapping package.
2012-09-11 20:44:15 +02:00
Oliver Gierke
13a69ecdfd DATAMONGO-533 - Fixed index creator registration.
In cases an ApplicationContext already contains a MongoPersistentEntityIndexCreator the default one is not registered, even if the one in the ApplicationContext listens to another MappingContext's events.

Polished iterable classes setup in MongoTemplate along the way. Some JavaDoc polishes as well.
2012-09-07 21:21:17 +02:00
Oliver Gierke
f0051deff0 Formatting. 2012-09-06 16:25:40 +02:00
Oliver Gierke
05a8148084 DATAMONGO-530 - Fixed propagation of setApplicationContext(…) in MappingMongoConverter. 2012-09-06 16:06:47 +02:00
Oliver Gierke
aaa44b3369 DATAMONGO-529 - Update Querydsl setup to use 1.0.4.
Raised Maven compiler plugin version to 2.5.1.
2012-09-06 15:48:41 +02:00
Oliver Gierke
7f35c4430d DATAMONGO-527 - Fixed Criteria.equals(…). 2012-09-03 18:47:25 +02:00
Oliver Gierke
114489d19a DATAMONGO-521 - Added test case to show that repository AND query works. 2012-09-03 16:46:53 +02:00
Oliver Gierke
eda8200d51 DATAMONGO-523 - Added test case to verify type alias detection. 2012-09-03 15:24:21 +02:00
Oliver Gierke
b078ea9ceb DATAMONGO-513 - Update to Spring Data Commons 1.4.0.BUILD-SNAPSHOT. 2012-09-03 15:24:20 +02:00
mpollack
d90b1a0ddd DATAMONGO-526 - Polished README.md.
Update README to remove references to old API, Docs links as well as CouchDB. Remove reference to Spring Data Document, copy initial paragraph introducing the project from http://www.springsource.org/spring-data/mongodb
2012-09-03 15:23:33 +02:00
Spring Buildmaster
737a42e07a DATAMONGO-513 - Prepare next development iteration. 2012-08-24 02:24:09 -07:00
Spring Buildmaster
22d5d4c019 DATAMONGO-513 - Release 1.1.0.RC1. 2012-08-24 02:24:06 -07:00
Oliver Gierke
7ac1e7b6e1 DATAMONGO-513 - Prepare changelog for 1.1.0.RC1. 2012-08-24 11:16:54 +02:00
Oliver Gierke
e86ab783f3 DATAMONGO-513 - Update to Spring Data Commons 1.4.0.RC1. 2012-08-23 20:12:41 +02:00
Oliver Gierke
6fe3e67ecb DATAMONGO-517 - Fixed complex keyword handling.
Introduced intermediate getMappedKeyword(Keyword keyword, MongoPersistentProperty property) to correctly return a DBObject for keyword plus converted value. A few refactorings and improvements in the implementation of QueryMapper (Keyword value object etc.).
2012-08-21 12:25:30 +02:00
Oliver Gierke
3b78034c55 DATAMONGO-519 - Make Spring 3.1.2.RELEASE default Spring dependency version.
We move away from Maven version ranges as they complicate the build and dependency resolution process. They make the build in-reproducible. Users stuck with a 3.0.x version of Spring will now have to manually declare Spring dependencies in their needed 3.0.x version. Not that at least Spring 3.0.7 is required currently.
2012-08-20 17:19:37 +02:00
Oliver Gierke
a06a69797f DATACMNS-214 - Adapted API change in Spring Data Commons.
Plus additional cleanups.
2012-08-16 14:10:02 +02:00
Oliver Gierke
8b1557e38c DATAMONGO-506 - Added test case to show BasicQuery is working for nested properties. 2012-08-15 19:40:02 +02:00
Oliver Gierke
fcdc6d0df2 DATAMONGO-511 - QueryMapper now maps associations correctly.
Complete overhaul of the QueryMapper to better handle complex scenarios like property paths and association references.
2012-08-15 18:30:29 +02:00
Oliver Gierke
83b6cd7f05 DATAMONGO-510 - Criteria now only uses BasicDBList internally. 2012-08-15 18:30:15 +02:00
Oliver Gierke
38a9a6d51d DATAMONGO-509 - SimpleMongoRepository.exists(…) now avoids loading unnecessary data.
We're explicitly ruling out the entities attributes via a field spec to avoid unnecessary object marshaling just to find out whether it exists or not.
2012-08-15 18:16:03 +02:00
Oliver Gierke
5e2f16c678 DATAMONGO-508 - Eagerly return DBRef creation if the given value already is a DBRef. 2012-08-15 16:38:56 +02:00
Oliver Gierke
d7ae95a779 DATAMONGO-505 - Fixed handling of parameter binding of associations and collection values.
Instead of converting given association values as-is, ConvertingParameterAccessor now converts each collection value into a DBRef individually.
2012-08-15 15:16:44 +02:00
Oliver Gierke
8fbdf9afbd DATACMNS-212 - Apply refactorings in Spring Data Commons. 2012-08-13 14:27:19 +02:00
Oliver Gierke
f5a4d78e62 DATAMONGO-476 - @EnableMongoRepositories is now inherited into sub-classes. 2012-08-13 11:37:59 +02:00
Oliver Gierke
1f4264e6a7 DATAMONGO-472 - MongoQueryCreator now correctly translates Not keyword.
We're now translating a negating property reference into a ne(…) call instead of a not().is(…).
2012-08-10 19:58:36 +02:00
Oliver Gierke
05baa851d8 DATAMONGO-502 - QueryMapper now translates property names into field names. 2012-08-08 18:56:18 +02:00
Oliver Gierke
35e8ae1224 DATAMONGO-500 - Index creation is only done for the correct MappingContext.
Index creation now double checks the MappingContext a MappingContextEvent originates from before actually creating indexes. This avoids invalid indexes being created in a multi-database scenario.
2012-07-31 15:34:50 +02:00
Oliver Gierke
ceec0bcc4a DATAMONGO-499 - Fixed namespace reference to repository XSD. 2012-07-31 10:39:03 +02:00
Oliver Gierke
0d87e7fa5f DATAMONGO-496 - AbstractMongoConfiguration now defaults mapping base package.
AbstractMappingConfiguration now uses the package of the class extending it to enable entity scanning for that package. To disable entity scanning entirely override the method to return null or an empty String.
2012-07-30 18:00:42 +02:00
Oliver Gierke
a530629d97 DATAMONGO-497 - Fixed reading of empty collections.
Reading an empty collection always returned a HashSet assuming the returned value would be converted into the assigned properties value later on. However the method should rather return the correct type already which we do now by invoking the potential conversion.
2012-07-30 15:39:22 +02:00
Oliver Gierke
ba0232b187 DATAMONGO-494 - QueryMapper now forwards entity metadata into nested $(n)or criterias.
Introduced helper class to ease assertions on DBObjects as well.
2012-07-27 10:39:31 +02:00
Oliver Gierke
04a17cacb7 DATAMONGO-495 - Fixed debug output in MongoTemplate.doFind(…).
Using SerializationUtils to safely output the query to be executed.
2012-07-26 10:35:30 +02:00
Oliver Gierke
761d725fce DATAMONGO-493 - Fixed broken $ne handling in QueryMapper.
$ne expressions are now only being tried to be converted into an ObjectId in case they follow an id property. Previously they tried in every case which might have led to Strings being converted into ObjectIds that accidentally were valid ObjectIds but didn't represent an id at all.
2012-07-24 20:43:52 +02:00
Oliver Gierke
726b0b1bcc DATAMONGO-493 - Added test case to show the described scenario is working. 2012-07-24 20:13:50 +02:00
Spring Buildmaster
888e031452 DATAMONGO-491 - Prepare next development iteration. 2012-07-24 07:57:13 -07:00
67 changed files with 2229 additions and 483 deletions

View File

@@ -1,16 +1,22 @@
Spring Data - Document
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.
As the name implies, the **Document** modules provides integration with document databases such as [MongoDB](http://www.mongodb.org/) and [CouchDB](http://couchdb.apache.org/).
The Spring Data MongoDB aims to provide a familiar and consistent Spring-based programming model for 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
Getting Help
------------
At this point your best bet is to look at the Look at the [JavaDocs](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/spring-data-mongodb/apidocs/) for MongoDB integration and corresponding and source code. For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80). If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects).
For a comprehensive treatmet of all the Spring Data MongoDB features, please refer to the The [User Guide](http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/)
The [User Guide](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/reference/html/) (A work in progress).
The [JavaDocs](http://static.springsource.org/spring-data/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.
For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80).
If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects).
Quick Start
@@ -137,11 +143,6 @@ This will register an object in the container named PersonRepository. You can u
}
## CouchDB
TBD
Contributing to Spring Data
---------------------------

View File

@@ -4,7 +4,9 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-dist</artifactId>
<name>Spring Data MongoDB Distribution</name>
<version>1.1.0.M2</version>
<description>Spring Data project for MongoDB</description>
<url>http://www.springsource.org/spring-data/mongodb</url>
<version>1.1.0.RELEASE</version>
<packaging>pom</packaging>
<modules>
<module>spring-data-mongodb</module>
@@ -288,4 +290,8 @@
</snapshotRepository>
</distributionManagement>
<scm>
<url>https://github.com/SpringSource/spring-data-mongodb</url>
</scm>
</project>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.1.0.M2</version>
<version>1.1.0.RELEASE</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-cross-store</artifactId>
@@ -42,7 +42,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.1.0.M2</version>
<version>1.1.0.RELEASE</version>
</dependency>
<dependency>

View File

@@ -4,16 +4,12 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.1.0.M2</version>
<version>1.1.0.RELEASE</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-log4j</artifactId>
<name>Spring Data MongoDB Log4J Appender</name>
<properties>
<mongo.version>2.3</mongo.version>
</properties>
<dependencies>
<!-- MongoDB -->

View File

@@ -4,21 +4,95 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<name>Spring Data MongoDB Parent</name>
<description>Spring Data project for MongoDB</description>
<url>http://www.springsource.org/spring-data/mongodb</url>
<version>1.1.0.M2</version>
<version>1.1.0.RELEASE</version>
<packaging>pom</packaging>
<developers>
<developer>
<id>trisberg</id>
<name>Thomas Risberg</name>
<email>trisberg at vmware.com</email>
<organization>SpringSource</organization>
<organizationUrl>http://www.SpringSource.com</organizationUrl>
<roles>
<role>Project Admin</role>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
<developer>
<id>mpollack</id>
<name>Mark Pollack</name>
<email>mpollack at vmware.com</email>
<organization>SpringSource</organization>
<organizationUrl>http://www.SpringSource.com</organizationUrl>
<roles>
<role>Project Admin</role>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
<developer>
<id>ogierke</id>
<name>Oliver Gierke</name>
<email>ogierke at vmware.com</email>
<organization>SpringSource</organization>
<organizationUrl>http://www.springsource.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>jbrisbin</id>
<name>Jon Brisbin</name>
<email>jbrisbin at vmware.com</email>
<organization>SpringSource</organization>
<organizationUrl>http://www.springsource.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>-6</timezone>
</developer>
</developers>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<comments>
Copyright 2010 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.
</comments>
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- versions for commonly-used dependencies -->
<mongo.version>2.9.1</mongo.version>
<junit.version>4.10</junit.version>
<log4j.version>1.2.16</log4j.version>
<org.mockito.version>1.9.0</org.mockito.version>
<org.slf4j.version>1.6.1</org.slf4j.version>
<org.codehaus.jackson.version>1.6.1</org.codehaus.jackson.version>
<org.springframework.version.30>3.0.7.RELEASE</org.springframework.version.30>
<org.springframework.version.40>4.0.0.RELEASE</org.springframework.version.40>
<org.springframework.version.range>[${org.springframework.version.30}, ${org.springframework.version.40})</org.springframework.version.range>
<data.commons.version>1.4.0.M1</data.commons.version>
<org.springframework.version.range>3.1.2.RELEASE</org.springframework.version.range>
<data.commons.version>1.4.0.RELEASE</data.commons.version>
<aspectj.version>1.6.11.RELEASE</aspectj.version>
<bundlor.failOnWarnings>true</bundlor.failOnWarnings>
</properties>
@@ -161,7 +235,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.4</version>
<version>2.5.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
@@ -245,11 +319,15 @@
<id>spring-plugins-release</id>
<url>http://repo.springsource.org/plugins-release</url>
</pluginRepository>
<pluginRepository>
<id>querydsl</id>
<url>http://source.mysema.com/maven2/releases</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
<id>spring-libs-release</id>
<url>http://repo.springsource.org/libs-release</url>
</repository>
</repositories>
<reporting>
@@ -269,4 +347,7 @@
</plugin>
</plugins>
</reporting>
<scm>
<url>https://github.com/SpringSource/spring-data-mongodb</url>
</scm>
</project>

View File

@@ -4,15 +4,14 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.1.0.M2</version>
<version>1.1.0.RELEASE</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb</artifactId>
<name>Spring Data MongoDB</name>
<properties>
<mongo.version>2.7.1</mongo.version>
<querydsl.version>2.6.0</querydsl.version>
<querydsl.version>2.8.0</querydsl.version>
<cdi.version>1.0</cdi.version>
<validation.version>1.0.0.GA</validation.version>
<webbeans.version>1.1.3</webbeans.version>
@@ -78,19 +77,6 @@
<artifactId>querydsl-mongodb</artifactId>
<version>${querydsl.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.google.code.morphia</groupId>
<artifactId>morphia</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -181,7 +167,14 @@
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0.2</version>
<version>1.0.4</version>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-test-sources</phase>

View File

@@ -39,7 +39,7 @@ import org.springframework.util.StringUtils;
import com.mongodb.Mongo;
/**
* Base class for Spring Data Mongo configuration using JavaConfig.
* Base class for Spring Data MongoDB configuration using JavaConfig.
*
* @author Mark Pollack
* @author Oliver Gierke
@@ -96,12 +96,16 @@ public abstract class AbstractMongoConfiguration {
}
/**
* Return the base package to scan for mapped {@link Document}s.
* Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
* {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is
* overriden to implement alternate behaviour.
*
* @return
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
* entities.
*/
protected String getMappingBasePackage() {
return null;
return getClass().getPackage().getName();
}
/**

View File

@@ -48,6 +48,7 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
@@ -166,27 +167,35 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
BeanDefinition conversionsDefinition) {
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
if (conversionsDefinition != null) {
AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
simpleTypesDefinition.setFactoryBeanName("customConversions");
simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
}
parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
if (StringUtils.hasText(ctxRef)) {
return ctxRef;
}
BeanComponentDefinitionBuilder componentDefinitionBuilder = new BeanComponentDefinitionBuilder(element,
parserContext);
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
if (conversionsDefinition != null) {
AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
simpleTypesDefinition.setFactoryBeanName("customConversions");
simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
}
parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
return ctxRef;
}

View File

@@ -79,21 +79,18 @@ public abstract class MongoDbUtils {
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
if (dbHolder != null && !dbHolder.isEmpty()) {
// Do we have a populated holder and TX sync active?
if (dbHolder != null && !dbHolder.isEmpty() && TransactionSynchronizationManager.isSynchronizationActive()) {
DB db = null;
DB db = dbHolder.getDB(databaseName);
if (TransactionSynchronizationManager.isSynchronizationActive() && dbHolder.doesNotHoldNonDefaultDB()) {
// DB found but not yet synchronized
if (db != null && !dbHolder.isSynchronizedWithTransaction()) {
db = dbHolder.getDB(databaseName);
LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName);
if (db != null && !dbHolder.isSynchronizedWithTransaction()) {
LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName);
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo));
dbHolder.setSynchronizedWithTransaction(true);
}
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo));
dbHolder.setSynchronizedWithTransaction(true);
}
if (db != null) {
@@ -101,6 +98,7 @@ public abstract class MongoDbUtils {
}
}
// Lookup fresh database instance
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
DB db = mongo.getDB(databaseName);
@@ -111,14 +109,15 @@ public abstract class MongoDbUtils {
String username = credentials.getUsername();
String password = credentials.hasPassword() ? credentials.getPassword() : null;
if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName
+ "], username = [" + username + "], password = [" + password + "]", databaseName, credentials);
synchronized (db) {
if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName
+ "], username = [" + username + "], password = [" + password + "]", databaseName, credentials);
}
}
}
// Use same Session for further Mongo actions within the transaction.
// Thread object will get removed by synchronization at transaction completion.
// TX sync active, bind new database to thread
if (TransactionSynchronizationManager.isSynchronizationActive()) {
LOGGER.debug("Registering Spring transaction synchronization for MongoDB instance {}.", databaseName);
@@ -162,7 +161,7 @@ public abstract class MongoDbUtils {
return false;
}
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
return (dbHolder != null && dbHolder.containsDB(db));
return dbHolder != null && dbHolder.containsDB(db);
}
/**

View File

@@ -16,13 +16,14 @@
package org.springframework.data.mongodb.core;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -37,6 +38,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
@@ -44,6 +46,7 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.mapping.PersistentEntity;
@@ -107,20 +110,24 @@ import com.mongodb.util.JSON;
* @author Mark Pollack
* @author Oliver Gierke
* @author Amol Nayak
* @author Patryk Wasik
*/
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class);
private static final String ID = "_id";
private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE;
@SuppressWarnings("serial")
private static final List<String> ITERABLE_CLASSES = new ArrayList<String>() {
{
add(List.class.getName());
add(Collection.class.getName());
add(Iterator.class.getName());
}
};
private static final Collection<String> ITERABLE_CLASSES;
static {
Set<String> iterableClasses = new HashSet<String>();
iterableClasses.add(List.class.getName());
iterableClasses.add(Collection.class.getName());
iterableClasses.add(Iterator.class.getName());
ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses);
}
/*
* WriteConcern to be used for write operations if it has been specified.
@@ -207,7 +214,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
}
}
}
/**
@@ -248,11 +254,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
this.readPreference = readPreference;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
String[] beans = applicationContext.getBeanNamesForType(MongoPersistentEntityIndexCreator.class);
if ((null == beans || beans.length == 0) && applicationContext instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) applicationContext).addApplicationListener(indexCreator);
}
prepareIndexCreator(applicationContext);
eventPublisher = applicationContext;
if (mappingContext instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
@@ -260,6 +269,30 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
resourceLoader = applicationContext;
}
/**
* Inspects the given {@link ApplicationContext} for {@link MongoPersistentEntityIndexCreator} and those in turn if
* they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext}
* can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get
* created appropriately for entity types persisted through this {@link MongoTemplate} instance.
*
* @param context
*/
private void prepareIndexCreator(ApplicationContext context) {
String[] indexCreators = context.getBeanNamesForType(MongoPersistentEntityIndexCreator.class);
for (String creator : indexCreators) {
MongoPersistentEntityIndexCreator creatorBean = context.getBean(creator, MongoPersistentEntityIndexCreator.class);
if (creatorBean.isIndexCreatorFor(mappingContext)) {
return;
}
}
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).addApplicationListener(indexCreator);
}
}
/**
* Returns the default {@link org.springframework.data.mongodb.core.core.convert.MongoConverter}.
*
@@ -337,7 +370,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: $s",
SerializationUtils.serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
}
this.executeQueryInternal(new FindCallback(queryObject, fieldsObject), preparer, dch, collectionName);
@@ -456,7 +489,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} else {
query.limit(1);
List<T> results = find(query, entityClass, collectionName);
return (results.isEmpty() ? null : results.get(0));
return results.isEmpty() ? null : results.get(0);
}
}
@@ -704,7 +737,53 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
public void save(Object objectToSave, String collectionName) {
doSave(collectionName, objectToSave, this.mongoConverter);
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(objectToSave.getClass());
// No optimistic locking -> simple save
if (!mongoPersistentEntity.hasVersionProperty()) {
doSave(collectionName, objectToSave, this.mongoConverter);
return;
}
doSaveVersioned(objectToSave, mongoPersistentEntity, collectionName);
}
private <T> void doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) {
BeanWrapper<PersistentEntity<T, ?>, T> beanWrapper = BeanWrapper.create(objectToSave,
this.mongoConverter.getConversionService());
MongoPersistentProperty idProperty = entity.getIdProperty();
MongoPersistentProperty versionProperty = entity.getVersionProperty();
Object id = beanWrapper.getProperty(idProperty);
// Fresh instance -> initialize version property
if (id == null) {
beanWrapper.setProperty(versionProperty, 0);
doSave(collectionName, objectToSave, this.mongoConverter);
} else {
assertUpdateableIdIfNotSet(objectToSave);
// Create query for entity with the id and old version
Object version = beanWrapper.getProperty(versionProperty);
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
// Bump version number
Number number = beanWrapper.getProperty(versionProperty, Number.class, false);
beanWrapper.setProperty(versionProperty, number.longValue() + 1);
BasicDBObject dbObject = new BasicDBObject();
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
this.mongoConverter.write(objectToSave, dbObject);
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject));
Update update = Update.fromDBObject(dbObject, ID);
updateFirst(query, update, objectToSave.getClass());
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject));
}
}
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
@@ -853,6 +932,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} else {
wr = collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
}
if (entity != null && entity.hasVersionProperty() && !multi) {
if (wr.getN() == 0) {
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObj.toMap().toString());
}
}
handleAnyWriteResultErrors(wr, queryObj, "update with '" + updateObj + "'");
return wr;
}
@@ -876,12 +963,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return;
}
remove(getIdQueryFor(object), collection);
doRemove(collection, getIdQueryFor(object), object.getClass());
}
/**
* Returns a {@link Query} for the given entity by its id.
*
*
* @param object must not be {@literal null}.
* @return
*/
@@ -1005,8 +1092,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
handleCommandError(commandResult, commandObject);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("MapReduce command result = [%s]",
SerializationUtils.serializeToJsonSafely(commandObject)));
LOGGER.debug(String.format("MapReduce command result = [%s]", serializeToJsonSafely(commandObject)));
}
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
@@ -1059,8 +1145,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBObject commandObject = new BasicDBObject("group", dbo);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Executing Group with DBObject [%s]",
SerializationUtils.serializeToJsonSafely(commandObject)));
LOGGER.debug(String.format("Executing Group with DBObject [%s]", serializeToJsonSafely(commandObject)));
}
CommandResult commandResult = executeCommand(commandObject, getDb().getOptions());
@@ -1172,7 +1257,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/**
* Create the specified collection using the provided options
*
*
* @param collectionName
* @param collectionOptions
* @return the collection that was created
@@ -1194,7 +1279,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter
* <p/>
* The query document is specified as a standard DBObject and so is the fields specification.
*
*
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1219,7 +1304,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* The query document is specified as a standard DBObject and so is the fields specification.
* <p/>
* Can be overridden by subclasses.
*
*
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1236,11 +1321,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
protected <S, T> List<T> doFind(String collectionName, DBObject query, DBObject fields, Class<S> entityClass,
CursorPreparer preparer, DbObjectCallback<T> objectCallback) {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("find using query: " + query + " fields: " + fields + " for class: " + entityClass
+ " in collection: " + collectionName);
LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
serializeToJsonSafely(query), fields, entityClass, collectionName));
}
return executeFindMultiInternal(new FindCallback(mapper.getMappedObject(query, entity), fields), preparer,
objectCallback, collectionName);
}
@@ -1249,7 +1337,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter.
* <p/>
* The query document is specified as a standard DBObject and so is the fields specification.
*
*
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1288,7 +1376,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* The first document that matches the query is returned and also removed from the collection in the database.
* <p/>
* The query document is specified as a standard DBObject and so is the fields specification.
*
*
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param entityClass the parameterized type of the returned list.
@@ -1335,7 +1423,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/**
* Populates the id property of the saved object, if it's not set already.
*
*
* @param savedObject
* @param id
*/
@@ -1354,21 +1442,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
ConversionService conversionService = mongoConverter.getConversionService();
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(savedObject, conversionService);
try {
Object idValue = wrapper.getProperty(idProp, idProp.getType(), true);
Object idValue = wrapper.getProperty(idProp, idProp.getType(), true);
if (idValue != null) {
return;
}
wrapper.setProperty(idProp, id);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
if (idValue != null) {
return;
}
wrapper.setProperty(idProp, id);
}
private DBCollection getAndPrepareCollection(DB db, String collectionName) {
@@ -1388,7 +1468,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* <li>Execute the given {@link ConnectionCallback} for a {@link DBObject}.</li>
* <li>Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.</li>
* <ol>
*
*
* @param <T>
* @param collectionCallback the callback to retrieve the {@link DBObject} with
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.mongodb.core.convert;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -253,13 +252,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
public void doWithAssociation(Association<MongoPersistentProperty> association) {
MongoPersistentProperty inverseProp = association.getInverse();
Object obj = getValueInternal(inverseProp, dbo, evaluator, result);
try {
wrapper.setProperty(inverseProp, obj);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
wrapper.setProperty(inverseProp, obj);
}
});
@@ -676,6 +671,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Assert.notNull(target);
if (target instanceof DBRef) {
return (DBRef) target;
}
MongoPersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
if (null == targetEntity) {
@@ -720,11 +719,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Assert.notNull(targetType);
Class<?> collectionType = targetType.getType();
if (sourceValue.isEmpty()) {
return new HashSet<Object>();
return getPotentiallyConvertedSimpleRead(new HashSet<Object>(), collectionType);
}
Class<?> collectionType = targetType.getType();
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -17,14 +17,16 @@ package org.springframework.data.mongodb.core.convert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.bson.types.BasicBSONList;
import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.util.Assert;
@@ -32,11 +34,12 @@ import org.springframework.util.Assert;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
/**
* A helper class to encapsulate any modifications of a Query object before it gets submitted to the database.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class QueryMapper {
@@ -46,6 +49,7 @@ public class QueryMapper {
private final ConversionService conversionService;
private final MongoConverter converter;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
/**
* Creates a new {@link QueryMapper} with the given {@link MongoConverter}.
@@ -53,9 +57,12 @@ public class QueryMapper {
* @param converter must not be {@literal null}.
*/
public QueryMapper(MongoConverter converter) {
Assert.notNull(converter);
this.conversionService = converter.getConversionService();
this.converter = converter;
this.mappingContext = converter.getMappingContext();
}
/**
@@ -68,47 +75,151 @@ public class QueryMapper {
*/
public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
DBObject newDbo = new BasicDBObject();
if (Keyword.isKeyword(query)) {
return getMappedKeyword(new Keyword(query), entity);
}
DBObject result = new BasicDBObject();
for (String key : query.keySet()) {
String newKey = key;
MongoPersistentProperty targetProperty = getTargetProperty(key, entity);
String newKey = determineKey(key, entity);
Object value = query.get(key);
if (isIdKey(key, entity)) {
if (value instanceof DBObject) {
DBObject valueDbo = (DBObject) value;
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
List<Object> ids = new ArrayList<Object>();
for (Object id : (Iterable<?>) valueDbo.get(inKey)) {
ids.add(convertId(id));
}
valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
} else {
value = getMappedObject((DBObject) value, null);
}
} else {
value = convertId(value);
}
newKey = "_id";
} else if (key.matches(N_OR_PATTERN)) {
// $or/$nor
Iterable<?> conditions = (Iterable<?>) value;
BasicBSONList newConditions = new BasicBSONList();
Iterator<?> iter = conditions.iterator();
while (iter.hasNext()) {
newConditions.add(getMappedObject((DBObject) iter.next(), null));
}
value = newConditions;
} else if (key.equals("$ne")) {
value = convertId(value);
}
newDbo.put(newKey, convertSimpleOrDBObject(value, null));
result.put(newKey, getMappedValue(value, targetProperty, newKey));
}
return newDbo;
return result;
}
/**
* 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 entity
* @return
*/
private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity<?> entity) {
// $or/$nor
if (query.key.matches(N_OR_PATTERN)) {
Iterable<?> conditions = (Iterable<?>) query.value;
BasicDBList newConditions = new BasicDBList();
for (Object condition : conditions) {
newConditions.add(getMappedObject((DBObject) condition, entity));
}
return new BasicDBObject(query.key, newConditions);
}
return new BasicDBObject(query.key, convertSimpleOrDBObject(query.value, entity));
}
/**
* Returns the mapped keyword considered defining a criteria for the given property.
*
* @param keyword
* @param property
* @return
*/
public DBObject getMappedKeyword(Keyword keyword, MongoPersistentProperty property) {
if (property.isAssociation()) {
convertAssociation(keyword.value, property);
}
return new BasicDBObject(keyword.key, getMappedValue(keyword.value, property, keyword.key));
}
/**
* Returns the mapped value for the given source object assuming it's a value for the given
* {@link MongoPersistentProperty}.
*
* @param source the source object to be mapped
* @param property the property the value is a value for
* @param newKey the key the value will be bound to eventually
* @return
*/
private Object getMappedValue(Object source, MongoPersistentProperty property, String newKey) {
if (property == null) {
return convertSimpleOrDBObject(source, null);
}
if (property.isIdProperty() || "_id".equals(newKey)) {
if (source instanceof DBObject) {
DBObject valueDbo = (DBObject) source;
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
List<Object> ids = new ArrayList<Object>();
for (Object id : (Iterable<?>) valueDbo.get(inKey)) {
ids.add(convertId(id));
}
valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
} else if (valueDbo.containsField("$ne")) {
valueDbo.put("$ne", convertId(valueDbo.get("$ne")));
} else {
return getMappedObject((DBObject) source, null);
}
return valueDbo;
} else {
return convertId(source);
}
}
if (property.isAssociation()) {
return Keyword.isKeyword(source) ? getMappedKeyword(new Keyword(source), property) : convertAssociation(source,
property);
}
return convertSimpleOrDBObject(source, mappingContext.getPersistentEntity(property));
}
private MongoPersistentProperty getTargetProperty(String key, MongoPersistentEntity<?> entity) {
if (isIdKey(key, entity)) {
return entity.getIdProperty();
}
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
return path == null ? null : path.getLeafProperty();
}
private PersistentPropertyPath<MongoPersistentProperty> getPath(String key, MongoPersistentEntity<?> entity) {
if (entity == null) {
return null;
}
try {
PropertyPath path = PropertyPath.from(key, entity.getTypeInformation());
return mappingContext.getPersistentPropertyPath(path);
} catch (PropertyReferenceException e) {
return null;
}
}
/**
* Returns the translated key assuming the given one is a propert (path) reference.
*
* @param key the source key
* @param entity the base entity
* @return the translated key
*/
private String determineKey(String key, MongoPersistentEntity<?> entity) {
if (entity == null && DEFAULT_ID_NAMES.contains(key)) {
return "_id";
}
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
return path == null ? key : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE);
}
/**
@@ -131,6 +242,30 @@ public class QueryMapper {
return converter.convertToMongoType(source);
}
/**
* Converts the given source assuming it's actually an association to anoter object.
*
* @param source
* @param property
* @return
*/
private Object convertAssociation(Object source, MongoPersistentProperty property) {
if (property == null || !property.isAssociation()) {
return source;
}
if (source instanceof Iterable) {
BasicDBList result = new BasicDBList();
for (Object element : (Iterable<?>) source) {
result.add(element instanceof DBRef ? element : converter.toDBRef(element, property));
}
return result;
}
return source instanceof DBRef ? source : converter.toDBRef(source, property);
}
/**
* Returns whether the given key will be considered an id key.
*
@@ -169,4 +304,44 @@ public class QueryMapper {
return converter.convertToMongoType(id);
}
/**
* Value object to capture a query keyword representation.
*
* @author Oliver Gierke
*/
private static class Keyword {
String key;
Object value;
Keyword(Object source) {
Assert.isInstanceOf(DBObject.class, source);
DBObject value = (DBObject) source;
Assert.isTrue(value.keySet().size() == 1, "Keyword must have a single key only!");
this.key = value.keySet().iterator().next();
this.value = value.get(key);
}
/**
* Returns whether the given value actually represents a keyword. If this returns {@literal true} it's safe to call
* the constructor.
*
* @param value
* @return
*/
static boolean isKeyword(Object value) {
if (!(value instanceof DBObject)) {
return false;
}
DBObject dbObject = (DBObject) value;
return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$");
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -13,37 +13,51 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.index;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.mapping.event.MappingContextEvent;
import org.springframework.data.mapping.context.MappingContextEvent;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
import org.springframework.util.Assert;
/**
* An implementation of ApplicationEventPublisher that will only fire MappingContextEvents for use by the index creator
* when MongoTemplate is used 'stand-alone', that is not declared inside a Spring ApplicationContext.
* An implementation of ApplicationEventPublisher that will only fire {@link MappingContextEvent}s for use by the index
* creator when MongoTemplate is used 'stand-alone', that is not declared inside a Spring {@link ApplicationContext}.
* Declare {@link MongoTemplate} inside an {@link ApplicationContext} to enable the publishing of all persistence events
* such as {@link AfterLoadEvent}, {@link AfterSaveEvent}, etc.
*
* Declare MongoTemplate inside an ApplicationContext to enable the publishing of all persistence events such as
* {@link AfterLoadEvent}, {@link AfterSaveEvent}, etc.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoMappingEventPublisher implements ApplicationEventPublisher {
private MongoPersistentEntityIndexCreator indexCreator;
private final MongoPersistentEntityIndexCreator indexCreator;
/**
* Creates a new {@link MongoMappingEventPublisher} for the given {@link MongoPersistentEntityIndexCreator}.
*
* @param indexCreator must not be {@literal null}.
*/
public MongoMappingEventPublisher(MongoPersistentEntityIndexCreator indexCreator) {
Assert.notNull(indexCreator);
this.indexCreator = indexCreator;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationEventPublisher#publishEvent(org.springframework.context.ApplicationEvent)
*/
@SuppressWarnings("unchecked")
public void publishEvent(ApplicationEvent event) {
if (event instanceof MappingContextEvent) {
indexCreator
.onApplicationEvent((MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty>) event);
indexCreator.onApplicationEvent((MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>) event);
}
}
}

View File

@@ -24,7 +24,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.event.MappingContextEvent;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.MappingContextEvent;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
@@ -44,25 +45,28 @@ import com.mongodb.util.JSON;
* @author Oliver Gierke
*/
public class MongoPersistentEntityIndexCreator implements
ApplicationListener<MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty>> {
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
private static final Logger log = LoggerFactory.getLogger(MongoPersistentEntityIndexCreator.class);
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<Class<?>, Boolean>();
private final MongoDbFactory mongoDbFactory;
private final MongoMappingContext mappingContext;
/**
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
* {@link MongoDbFactory}.
*
* @param mappingContext must not be {@@iteral null}
* @param mongoDbFactory must not be {@@iteral null}
* @param mappingContext must not be {@literal null}
* @param mongoDbFactory must not be {@literal null}
*/
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) {
Assert.notNull(mongoDbFactory);
Assert.notNull(mappingContext);
this.mongoDbFactory = mongoDbFactory;
this.mappingContext = mappingContext;
for (MongoPersistentEntity<?> entity : mappingContext.getPersistentEntities()) {
checkForIndexes(entity);
@@ -73,8 +77,11 @@ public class MongoPersistentEntityIndexCreator implements
* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(
MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty> event) {
public void onApplicationEvent(MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty> event) {
if (!event.wasEmittedBy(mappingContext)) {
return;
}
PersistentEntity<?, ?> entity = event.getPersistentEntity();
@@ -163,6 +170,26 @@ public class MongoPersistentEntityIndexCreator implements
}
}
/**
* Returns whether the current index creator was registered for the given {@link MappingContext}.
*
* @param context
* @return
*/
public boolean isIndexCreatorFor(MappingContext<?, ?> context) {
return this.mappingContext.equals(context);
}
/**
* Triggers the actual index creation.
*
* @param collection the collection to create the index in
* @param name the name of the index about to be created
* @param indexDefinition the index definition
* @param unique whether it shall be a unique index
* @param dropDups whether to drop duplicates
* @param sparse sparse or not
*/
protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique,
boolean dropDups, boolean sparse) {

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.mapping;
import java.util.Comparator;
@@ -23,8 +22,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoCollectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.Expression;
@@ -34,11 +33,12 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;
/**
* Mongo specific {@link PersistentEntity} implementation that adds Mongo specific meta-data such as the collection name
* and the like.
* MongoDB specific {@link MongoPersistentEntity} implementation that adds Mongo specific meta-data such as the
* collection name and the like.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Jon Brisbin
* @author Oliver Gierke
* @author Patryk Wasik
*/
public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, MongoPersistentProperty> implements
MongoPersistentEntity<T>, ApplicationContextAware {
@@ -47,6 +47,8 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
private final SpelExpressionParser parser;
private final StandardEvaluationContext context;
private MongoPersistentProperty versionProperty;
/**
* Creates a new {@link BasicMongoPersistentEntity} with the given {@link TypeInformation}. Will default the
* collection name to the entities simple type name.
@@ -71,20 +73,41 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
*/
@Override
public void addPersistentProperty(MongoPersistentProperty property) {
if (property.isVersionProperty()) {
if (this.versionProperty != null) {
throw new MappingException(String.format(
"Attempt to add version property %s but already have property %s registered "
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
}
this.versionProperty = property;
}
super.addPersistentProperty(property);
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
}
/**
* Returns the collection the entity should be stored in.
*
* @return
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getCollection()
*/
public String getCollection() {
@@ -92,6 +115,22 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
return expression.getValue(context, String.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getVersionProperty()
*/
public MongoPersistentProperty getVersionProperty() {
return versionProperty;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#hasVersionProperty()
*/
public boolean hasVersionProperty() {
return getVersionProperty() != null;
}
/**
* {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order.
*

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -32,9 +32,10 @@ import org.springframework.util.StringUtils;
import com.mongodb.DBObject;
/**
* Mongo specific {@link org.springframework.data.mapping.PersistentProperty} implementation.
* MongoDB specific {@link org.springframework.data.mapping.MongoPersistentProperty} implementation.
*
* @author Oliver Gierke
* @author Patryk Wasik
*/
public class BasicMongoPersistentProperty extends AnnotationBasedPersistentProperty<MongoPersistentProperty> implements
MongoPersistentProperty {
@@ -112,8 +113,9 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
return annotation != null && StringUtils.hasText(annotation.value()) ? annotation.value() : field.getName();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#getFieldOrder()
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder()
*/
public int getFieldOrder() {
org.springframework.data.mongodb.core.mapping.Field annotation = getField().getAnnotation(
@@ -121,25 +123,36 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
return annotation != null ? annotation.order() : Integer.MAX_VALUE;
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractPersistentProperty#createAssociation()
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
*/
@Override
protected Association<MongoPersistentProperty> createAssociation() {
return new Association<MongoPersistentProperty>(this, null);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#isDbReference()
*/
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isDbReference()
*/
public boolean isDbReference() {
return getField().isAnnotationPresent(DBRef.class);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#getDBRef()
*/
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getDBRef()
*/
public DBRef getDBRef() {
return getField().getAnnotation(DBRef.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isVersionProperty()
*/
public boolean isVersionProperty() {
return getField().isAnnotationPresent(Version.class);
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.mapping;
import java.beans.PropertyDescriptor;
@@ -23,12 +22,16 @@ import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke ogierke@vmware.com
* Default implementation of a {@link MappingContext} for MongoDB using {@link BasicMongoPersistentEntity} and
* {@link BasicMongoPersistentProperty} as primary abstractions.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersistentEntity<?>, MongoPersistentProperty>
implements ApplicationContextAware {
@@ -42,6 +45,15 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
setSimpleTypeHolder(MongoSimpleTypes.HOLDER);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.AbstractMappingContext#shouldCreatePersistentEntityFor(org.springframework.data.util.TypeInformation)
*/
@Override
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder)
@@ -72,7 +84,10 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
super.setApplicationContext(applicationContext);
}
}

View File

@@ -1,12 +1,49 @@
/*
* Copyright 2011-2012 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.mapping;
import org.springframework.data.mapping.PersistentEntity;
/**
* MongoDB specific {@link PersistentEntity} abstraction.
*
* @author Oliver Gierke
* @author Patryk Wasik
*/
public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersistentProperty> {
/**
* Returns the collection the entity shall be persisted to.
*
* @return
*/
String getCollection();
/**
* Returns the {@link MongoPersistentProperty} that represents the version attribute of an entity. Will not be
* {@literal null} if {@link #hasVersionProperty()}.
*
* @return
*/
MongoPersistentProperty getVersionProperty();
/**
* Returns whether the entity has a property representing the version of the entity.
*
* @return
*/
boolean hasVersionProperty();
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -19,9 +19,10 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.PersistentProperty;
/**
* Mongo specific {@link org.springframework.data.mapping.PersistentProperty} implementation.
* MongoDB specific {@link org.springframework.data.mapping.PersistentProperty} extension.
*
* @author Oliver Gierke
* @author Patryk Wasik
*/
public interface MongoPersistentProperty extends PersistentProperty<MongoPersistentProperty> {
@@ -55,6 +56,13 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
*/
DBRef getDBRef();
/**
* Returns whether the property is representing the version attribute of an entity.
*
* @return
*/
boolean isVersionProperty();
/**
* Simple {@link Converter} implementation to transform a {@link MongoPersistentProperty} into its field name.
*

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2012-2012 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
* 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,
@@ -29,22 +29,25 @@ import org.springframework.data.mongodb.MongoCollectionUtils;
import org.springframework.data.util.TypeInformation;
/**
*
* @deprecated use {@link MongoMappingContext} instead.
* @author Oliver Gierke
*/
@Deprecated
public class SimpleMongoMappingContext extends
AbstractMappingContext<SimpleMongoMappingContext.SimpleMongoPersistentEntity<?>, MongoPersistentProperty> {
/* (non-Javadoc)
* @see org.springframework.data.mapping.BasicMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
*/
@Override
protected <T> SimpleMongoPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
return new SimpleMongoPersistentEntity<T>(typeInformation);
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.BasicMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.util.TypeInformation, org.springframework.data.mapping.BasicPersistentEntity)
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
*/
@Override
protected SimplePersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
@@ -112,6 +115,14 @@ public class SimpleMongoMappingContext extends
public DBRef getDBRef() {
return null;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#isVersion()
*/
public boolean isVersionProperty() {
return false;
}
}
static class SimpleMongoPersistentEntity<T> extends BasicPersistentEntity<T, MongoPersistentProperty> implements
@@ -130,5 +141,20 @@ public class SimpleMongoMappingContext extends
public String getCollection() {
return MongoCollectionUtils.getPreferredCollectionName(getType());
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentEntity#getVersionProperty()
*/
public MongoPersistentProperty getVersionProperty() {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#hasVersionProperty()
*/
public boolean hasVersionProperty() {
return false;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2012 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.mapping;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Demarcates a property to be used as version field to implement optimistic locking on entities.
*
* @since 1.4
* @author Patryk Wasik
*/
@Documented
@Target({ FIELD })
@Retention(RUNTIME)
public @interface Version {
}

View File

@@ -25,7 +25,6 @@ import java.util.List;
import java.util.regex.Pattern;
import org.bson.BSON;
import org.bson.types.BasicBSONList;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.core.geo.Circle;
import org.springframework.data.mongodb.core.geo.Point;
@@ -33,6 +32,7 @@ import org.springframework.data.mongodb.core.geo.Shape;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@@ -400,7 +400,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria
*/
public Criteria orOperator(Criteria... criteria) {
BasicBSONList bsonList = createCriteriaList(criteria);
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$or").is(bsonList));
return this;
}
@@ -411,7 +411,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria
*/
public Criteria norOperator(Criteria... criteria) {
BasicBSONList bsonList = createCriteriaList(criteria);
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$nor").is(bsonList));
return this;
}
@@ -422,7 +422,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria
*/
public Criteria andOperator(Criteria... criteria) {
BasicBSONList bsonList = createCriteriaList(criteria);
BasicDBList bsonList = createCriteriaList(criteria);
criteriaChain.add(new Criteria("$and").is(bsonList));
return this;
}
@@ -478,8 +478,8 @@ public class Criteria implements CriteriaDefinition {
return queryCriteria;
}
private BasicBSONList createCriteriaList(Criteria[] criteria) {
BasicBSONList bsonList = new BasicBSONList();
private BasicDBList createCriteriaList(Criteria[] criteria) {
BasicDBList bsonList = new BasicDBList();
for (Criteria c : criteria) {
bsonList.add(c.getCriteriaObject());
}
@@ -514,9 +514,28 @@ public class Criteria implements CriteriaDefinition {
Criteria that = (Criteria) obj;
boolean keyEqual = this.key == null ? that.key == null : this.key.equals(that.key);
boolean criteriaEqual = this.criteria.equals(that.criteria);
boolean valueEqual = isEqual(this.isValue, that.isValue);
if (this.criteriaChain.size() != that.criteriaChain.size()) {
return false;
}
for (int i = 0; i < this.criteriaChain.size(); i++) {
Criteria left = this.criteriaChain.get(i);
Criteria right = that.criteriaChain.get(i);
if (!simpleCriteriaEquals(left, right)) {
return false;
}
}
return true;
}
private boolean simpleCriteriaEquals(Criteria left, Criteria right) {
boolean keyEqual = left.key == null ? right.key == null : left.key.equals(right.key);
boolean criteriaEqual = left.criteria.equals(right.criteria);
boolean valueEqual = isEqual(left.isValue, right.isValue);
return keyEqual && criteriaEqual && valueEqual;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,24 +15,32 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.springframework.data.mongodb.core.SerializationUtils.*;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import static org.springframework.util.ObjectUtils.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* @author Thomas Risberg
* @author Oliver Gierke
*/
public class Query {
private LinkedHashMap<String, Criteria> criteria = new LinkedHashMap<String, Criteria>();
private Field fieldSpec;
private Sort sort;
private Sort coreSort;
@SuppressWarnings("deprecation")
private org.springframework.data.mongodb.core.query.Sort sort;
private int skip;
private int limit;
private String hint;
@@ -96,14 +104,61 @@ public class Query {
return this;
}
public Sort sort() {
/**
* Returns a {@link org.springframework.data.mongodb.core.query.Sort} instance to define ordering properties.
*
* @deprecated use {@link #with(Sort)} instead
* @return
*/
@Deprecated
public org.springframework.data.mongodb.core.query.Sort sort() {
if (this.sort == null) {
this.sort = new Sort();
this.sort = new org.springframework.data.mongodb.core.query.Sort();
}
return this.sort;
}
/**
* Sets the given pagination information on the {@link Query} instance. Will transparently set {@code skip} and
* {@code limit} as well as applying the {@link Sort} instance defined with the {@link Pageable}.
*
* @param pageable
* @return
*/
public Query with(Pageable pageable) {
if (pageable == null) {
return this;
}
this.limit = pageable.getPageSize();
this.skip = pageable.getOffset();
return with(pageable.getSort());
}
/**
* Adds a {@link Sort} to the {@link Query} instance.
*
* @param sort
* @return
*/
public Query with(Sort sort) {
if (sort == null) {
return this;
}
if (this.coreSort == null) {
this.coreSort = sort;
} else {
this.coreSort = this.coreSort.and(sort);
}
return this;
}
public DBObject getQueryObject() {
DBObject dbo = new BasicDBObject();
for (String k : criteria.keySet()) {
@@ -121,11 +176,26 @@ public class Query {
return fieldSpec.getFieldsObject();
}
@SuppressWarnings("deprecation")
public DBObject getSortObject() {
if (this.sort == null) {
if (this.coreSort == null && this.sort == null) {
return null;
}
return this.sort.getSortObject();
DBObject dbo = new BasicDBObject();
if (this.coreSort != null) {
for (org.springframework.data.domain.Sort.Order order : this.coreSort) {
dbo.put(order.getProperty(), order.isAscending() ? 1 : -1);
}
}
if (this.sort != null) {
dbo.putAll(this.sort.getSortObject());
}
return dbo;
}
public int getSkip() {

View File

@@ -13,7 +13,7 @@
* 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.query;
import java.util.Collection;
import java.util.Iterator;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,15 @@ import java.util.Map;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Helper class to define sorting criterias for a Query instance.
*
* @author Thomas Risberg
* @author Oliver Gierke
* @deprecated use {@link org.springframework.data.domain.Sort} instead. See
* {@link Query#with(org.springframework.data.domain.Sort)}.
*/
@Deprecated
public class Sort {
private Map<String, Order> fieldSpec = new LinkedHashMap<String, Order>();
@@ -40,7 +49,7 @@ public class Sort {
public DBObject getSortObject() {
DBObject dbo = new BasicDBObject();
for (String k : fieldSpec.keySet()) {
dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1));
dbo.put(k, fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1);
}
return dbo;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,13 +15,23 @@
*/
package org.springframework.data.mongodb.core.query;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.dao.InvalidDataAccessApiUsageException;
/**
* Class to easily construct MongoDB update clauses.
*
* @author Thomas Risberg
* @author Mark Pollack
* @author Oliver Gierke
*/
public class Update {
public enum Position {
@@ -40,6 +50,31 @@ public class Update {
return new Update().set(key, value);
}
/**
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exlude fields from making
* it into the created {@link Update} object.
*
* @param object the source {@link DBObject} to create the update from.
* @param exclude the fields to exclude.
* @return
*/
public static Update fromDBObject(DBObject object, String... exclude) {
Update update = new Update();
List<String> excludeList = Arrays.asList(exclude);
for (String key : object.keySet()) {
if (excludeList.contains(key)) {
continue;
}
update.set(key, object.get(key));
}
return update;
}
/**
* Update using the $set update modifier
*

View File

@@ -19,6 +19,7 @@ import java.io.InputStream;
import java.util.List;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.DBObject;
@@ -63,8 +64,10 @@ public interface GridFsOperations extends ResourcePatternResolver {
GridFSFile store(InputStream content, String filename, DBObject metadata);
/**
* Returns all files matching the given query.
* Returns all files matching the given query. Note, that currently {@link Sort} criterias defined at the
* {@link Query} will not be regarded as MongoDB does not support ordering for GridFS file access.
*
* @see https://jira.mongodb.org/browse/JAVA-431
* @param query
* @return
*/
@@ -102,4 +105,4 @@ public interface GridFsOperations extends ResourcePatternResolver {
* @see ResourcePatternResolver#getResources(String)
*/
GridFsResource[] getResources(String filenamePattern);
}
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.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;
@@ -38,6 +39,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(MongoRepositoriesRegistrar.class)
public @interface EnableMongoRepositories {

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.mongodb.repository.query;
import static org.springframework.data.mongodb.repository.query.QueryUtils.*;
import java.util.List;
import org.springframework.data.domain.PageImpl;
@@ -145,12 +143,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
*/
@Override
public Object execute(Query query) {
if (pageable != null) {
query = applyPagination(query, pageable);
}
return readCollection(query);
return readCollection(query.with(pageable));
}
}
@@ -185,8 +178,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
MongoEntityInformation<?, ?> metadata = method.getEntityInformation();
long count = operations.count(query, metadata.getCollectionName());
List<?> result = operations.find(applyPagination(query, pageable), metadata.getJavaType(),
metadata.getCollectionName());
List<?> result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName());
return new PageImpl(result, pageable, count);
}

View File

@@ -15,7 +15,11 @@
*/
package org.springframework.data.mongodb.repository.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -25,6 +29,9 @@ import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import com.mongodb.DBRef;
/**
* Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format.
@@ -158,7 +165,28 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
* @see org.springframework.data.mongodb.repository.ConvertingParameterAccessor.PotentiallConvertingIterator#nextConverted()
*/
public Object nextConverted(MongoPersistentProperty property) {
return property.isAssociation() ? writer.toDBRef(next(), property) : getConvertedValue(next());
Object next = next();
if (next == null) {
return null;
}
if (property.isAssociation()) {
if (next.getClass().isArray() || next instanceof Iterable) {
List<DBRef> dbRefs = new ArrayList<DBRef>();
for (Object element : asCollection(next)) {
dbRefs.add(writer.toDBRef(element, property));
}
return dbRefs;
} else {
return writer.toDBRef(next, property);
}
}
return getConvertedValue(next);
}
/*
@@ -170,6 +198,33 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
}
}
/**
* Returns the given object as {@link Collection}. Will do a copy of it if it implements {@link Iterable} or is an
* array. Will return an empty {@link Collection} in case {@literal null} is given. Will wrap all other types into a
* single-element collction
*
* @param source
* @return
*/
private static Collection<?> asCollection(Object source) {
if (source instanceof Iterable) {
List<Object> result = new ArrayList<Object>();
for (Object element : (Iterable<?>) source) {
result.add(element);
}
return result;
}
if (source == null) {
return Collections.emptySet();
}
return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source);
}
/**
* Custom {@link Iterator} that adds a method to access elements in a converted manner.
*

View File

@@ -147,8 +147,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
return null;
}
Query query = new Query(criteria);
QueryUtils.applySorting(query, sort);
Query query = new Query(criteria).with(sort);
if (LOG.isDebugEnabled()) {
LOG.debug("Created query " + query);
@@ -228,7 +227,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
case SIMPLE_PROPERTY:
return criteria.is(parameters.nextConverted(property));
case NEGATING_SIMPLE_PROPERTY:
return criteria.not().is(parameters.nextConverted(property));
return criteria.ne(parameters.nextConverted(property));
}
throw new IllegalArgumentException("Unsupported keyword!");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,13 @@
*/
package org.springframework.data.mongodb.repository.query;
import com.mongodb.DBCursor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.DBCursor;
/**
* Collection of utility methods to apply sorting and pagination to a {@link DBCursor}.
*
@@ -36,10 +37,12 @@ public abstract class QueryUtils {
* Applies the given {@link Pageable} to the given {@link Query}. Will do nothing if {@link Pageable} is
* {@literal null}.
*
* @param query
* @deprecated use {@link Query#with(Pageable)}.
* @param query must not be {@literal null}.
* @param pageable
* @return
*/
@Deprecated
public static Query applyPagination(Query query, Pageable pageable) {
if (pageable == null) {
@@ -49,16 +52,18 @@ public abstract class QueryUtils {
query.limit(pageable.getPageSize());
query.skip(pageable.getOffset());
return applySorting(query, pageable.getSort());
return query.with(pageable.getSort());
}
/**
* Applies the given {@link Sort} to the {@link Query}. Will do nothing if {@link Sort} is {@literal null}.
*
* @param query
* @deprecated use {@link Query#with(Pageable)}.
* @param query must not be {@literal null}.
* @param sort
* @return
*/
@Deprecated
public static Query applySorting(Query query, Sort sort) {
if (sort == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 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.
@@ -73,7 +73,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
query = new BasicQuery(queryString);
}
QueryUtils.applySorting(query, accessor.getSort());
query.with(accessor.getSort());
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Created query %s", query.getQueryObject()));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 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.
@@ -34,7 +34,6 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.query.QueryUtils;
import org.springframework.util.Assert;
/**
@@ -115,8 +114,11 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
public boolean exists(ID id) {
Assert.notNull(id, "The given id must not be null!");
return mongoOperations.findOne(new Query(Criteria.where("_id").is(id)), Object.class,
entityInformation.getCollectionName()) != null;
final Query idQuery = getIdQuery(id);
idQuery.fields();
return mongoOperations.findOne(idQuery, entityInformation.getJavaType(), entityInformation.getCollectionName()) != null;
}
/*
@@ -197,7 +199,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
public Page<T> findAll(final Pageable pageable) {
Long count = count();
List<T> list = findAll(QueryUtils.applyPagination(new Query(), pageable));
List<T> list = findAll(new Query().with(pageable));
return new PageImpl<T>(list, pageable, count);
}
@@ -206,9 +208,8 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
* (non-Javadoc)
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
public List<T> findAll(final Sort sort) {
return findAll(QueryUtils.applySorting(new Query(), sort));
public List<T> findAll(Sort sort) {
return findAll(new Query().with(sort));
}
private List<T> findAll(Query query) {

View File

@@ -14,7 +14,7 @@
<xsd:import namespace="http://www.springframework.org/schema/context"
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd" />
<xsd:element name="mongo" type="mongoType">
<xsd:annotation>
@@ -44,8 +44,9 @@ The name of the mongo definition (by default "mongoDbFactory").]]></xsd:document
</xsd:attribute>
<xsd:attribute name="mongo-ref" type="mongoRef" use="optional">
<xsd:annotation>
<xsd:documentation>
The reference to a Mongo. Will default to 'mongo'.
<xsd:documentation><![CDATA[
The reference to a Mongo instance. If not configured a default com.mongodb.Mongo instance will be created.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -44,8 +44,9 @@ The name of the mongo definition (by default "mongoDbFactory").]]></xsd:document
</xsd:attribute>
<xsd:attribute name="mongo-ref" type="mongoRef" use="optional">
<xsd:annotation>
<xsd:documentation>
The reference to a Mongo. Will default to 'mongo'.
<xsd:documentation><![CDATA[
The reference to a Mongo instance. If not configured a default com.mongodb.Mongo instance will be created.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2012 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.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.mapping.Document;
import com.mongodb.Mongo;
/**
* Unit tests for {@link AbstractMongoConfiguration}.
*
* @author Oliver Gierke
*/
public class AbstractMongoConfigurationUnitTests {
/**
* @see DATAMONGO-496
*/
@Test
public void usesConfigClassPackageAsBaseMappingPackage() throws ClassNotFoundException {
AbstractMongoConfiguration configuration = new SampleMongoConfiguration();
assertThat(configuration.getMappingBasePackage(), is(SampleMongoConfiguration.class.getPackage().getName()));
assertThat(configuration.getInitialEntitySet(), hasSize(1));
assertThat(configuration.getInitialEntitySet(), hasItem(Entity.class));
}
/**
* @see DATAMONGO-496
*/
@Test
public void doesNotScanPackageIfMappingPackageIsNull() throws ClassNotFoundException {
assertScanningDisabled(null);
}
/**
* @see DATAMONGO-496
*/
@Test
public void doesNotScanPackageIfMappingPackageIsEmpty() throws ClassNotFoundException {
assertScanningDisabled("");
assertScanningDisabled(" ");
}
private static void assertScanningDisabled(final String value) throws ClassNotFoundException {
AbstractMongoConfiguration configuration = new SampleMongoConfiguration() {
@Override
protected String getMappingBasePackage() {
return value;
}
};
assertThat(configuration.getMappingBasePackage(), is(value));
assertThat(configuration.getInitialEntitySet(), hasSize(0));
}
static class SampleMongoConfiguration extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "database";
}
@Bean
@Override
public Mongo mongo() throws Exception {
return new Mongo();
}
}
@Document
static class Entity {
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import com.mongodb.BasicDBList;
import com.mongodb.DBObject;
/**
* Helper classes to ease assertions on {@link DBObject}s.
*
* @author Oliver Gierke
*/
public abstract class DBObjectUtils {
private DBObjectUtils() {
}
/**
* Expects the field with the given key to be not {@literal null} and a {@link DBObject} in turn and returns it.
*
* @param source the {@link DBObject} to lookup the nested one
* @param key the key of the field to lokup the nested {@link DBObject}
* @return
*/
public static DBObject getAsDBObject(DBObject source, String key) {
return getTypedValue(source, key, DBObject.class);
}
/**
* Expects the field with the given key to be not {@literal null} and a {@link BasicDBList}.
*
* @param source the {@link DBObject} to lookup the {@link BasicDBList} in
* @param key the key of the field to find the {@link BasicDBList} in
* @return
*/
public static BasicDBList getAsDBList(DBObject source, String key) {
return getTypedValue(source, key, BasicDBList.class);
}
/**
* Expects the list element with the given index to be a non-{@literal null} {@link DBObject} and returns it.
*
* @param source the {@link BasicDBList} to look up the {@link DBObject} element in
* @param index the index of the element expected to contain a {@link DBObject}
* @return
*/
public static DBObject getAsDBObject(BasicDBList source, int index) {
assertThat(source.size(), greaterThanOrEqualTo(index + 1));
Object value = source.get(index);
assertThat(value, is(instanceOf(DBObject.class)));
return (DBObject) value;
}
@SuppressWarnings("unchecked")
private static <T> T getTypedValue(DBObject source, String key, Class<T> type) {
Object value = source.get(key);
assertThat(value, is(notNullValue()));
assertThat(value, is(instanceOf(type)));
return (T) value;
}
}

View File

@@ -17,10 +17,17 @@ package org.springframework.data.mongodb.core;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.mongodb.DB;
@@ -31,13 +38,21 @@ import com.mongodb.Mongo;
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class MongoDbUtilsUnitTests {
@Mock
Mongo mongo;
@Before
public void setUp() throws Exception {
this.mongo = new Mongo();
when(mongo.getDB(anyString())).then(new Answer<DB>() {
public DB answer(InvocationOnMock invocation) throws Throwable {
return mock(DB.class);
}
});
TransactionSynchronizationManager.initSynchronization();
}
@@ -55,11 +70,15 @@ public class MongoDbUtilsUnitTests {
public void returnsNewInstanceForDifferentDatabaseName() {
DB first = MongoDbUtils.getDB(mongo, "first");
assertThat(first, is(notNullValue()));
assertThat(MongoDbUtils.getDB(mongo, "first"), is(first));
DB second = MongoDbUtils.getDB(mongo, "second");
assertThat(second, is(not(first)));
assertThat(MongoDbUtils.getDB(mongo, "second"), is(second));
}
@Test
public void returnsSameInstanceForSameDatabaseName() {
DB first = MongoDbUtils.getDB(mongo, "first");
assertThat(first, is(notNullValue()));
assertThat(MongoDbUtils.getDB(mongo, "first"), is(sameInstance(first)));
}
}

View File

@@ -40,6 +40,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
@@ -51,6 +52,7 @@ import org.springframework.data.mongodb.core.index.Index.Duplicates;
import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Order;
import org.springframework.data.mongodb.core.query.Query;
@@ -74,6 +76,7 @@ import com.mongodb.WriteResult;
* @author Oliver Gierke
* @author Thomas Risberg
* @author Amol Nayak
* @author Patryk Wasik
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
@@ -123,18 +126,20 @@ public class MongoTemplateTests {
}
protected void cleanDb() {
template.dropCollection(template.getCollectionName(Person.class));
template.dropCollection(template.getCollectionName(PersonWithAList.class));
template.dropCollection(template.getCollectionName(PersonWith_idPropertyOfTypeObjectId.class));
template.dropCollection(template.getCollectionName(PersonWith_idPropertyOfTypeString.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeObjectId.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeString.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeInteger.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfPrimitiveInt.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfTypeLong.class));
template.dropCollection(template.getCollectionName(PersonWithIdPropertyOfPrimitiveLong.class));
template.dropCollection(template.getCollectionName(TestClass.class));
template.dropCollection(Person.class);
template.dropCollection(PersonWithAList.class);
template.dropCollection(PersonWith_idPropertyOfTypeObjectId.class);
template.dropCollection(PersonWith_idPropertyOfTypeString.class);
template.dropCollection(PersonWithIdPropertyOfTypeObjectId.class);
template.dropCollection(PersonWithIdPropertyOfTypeString.class);
template.dropCollection(PersonWithIdPropertyOfTypeInteger.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class);
template.dropCollection(PersonWithIdPropertyOfTypeLong.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class);
template.dropCollection(PersonWithVersionPropertyOfTypeInteger.class);
template.dropCollection(TestClass.class);
template.dropCollection(Sample.class);
template.dropCollection(MyPerson.class);
}
@Test
@@ -1232,6 +1237,91 @@ public class MongoTemplateTests {
template.remove(query(where("id").is(id)), TypeWithMyId.class);
}
/**
* @see DATAMONGO-506
*/
@Test
public void exceutesBasicQueryCorrectly() {
Address address = new Address();
address.state = "PA";
address.city = "Philadelphia";
MyPerson person = new MyPerson();
person.name = "Oleg";
person.address = address;
template.save(person);
Query query = new BasicQuery("{'name' : 'Oleg'}");
List<MyPerson> result = template.find(query, MyPerson.class);
assertThat(result, hasSize(1));
assertThat(result.get(0), hasProperty("name", is("Oleg")));
query = new BasicQuery("{'address.state' : 'PA' }");
result = template.find(query, MyPerson.class);
assertThat(result, hasSize(1));
assertThat(result.get(0), hasProperty("name", is("Oleg")));
}
/**
* @see DATAMONGO-279
*/
@Test(expected = OptimisticLockingFailureException.class)
public void optimisticLockingHandling() {
// Init version
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.age = 29;
person.firstName = "Patryk";
template.save(person);
List<PersonWithVersionPropertyOfTypeInteger> result = template
.findAll(PersonWithVersionPropertyOfTypeInteger.class);
assertThat(result, hasSize(1));
assertThat(result.get(0).version, is(0));
// Version change
person = result.get(0);
person.firstName = "Patryk2";
template.save(person);
assertThat(person.version, is(1));
result = mappingTemplate.findAll(PersonWithVersionPropertyOfTypeInteger.class);
assertThat(result, hasSize(1));
assertThat(result.get(0).version, is(1));
// Optimistic lock exception
person.version = 0;
person.firstName = "Patryk3";
template.save(person);
}
/**
* @see DATAMONGO-539
*/
@Test
public void removesObjectFromExplicitCollection() {
String collectionName = "explicit";
template.remove(new Query(), collectionName);
PersonWithConvertedId person = new PersonWithConvertedId();
person.name = "Dave";
template.save(person, collectionName);
assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(false));
template.remove(person, collectionName);
assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(true));
}
static class MyId {
String first;
@@ -1261,6 +1351,12 @@ public class MongoTemplateTests {
}
}
static class PersonWithConvertedId {
String id;
String name;
}
static enum DateTimeToDateConverter implements Converter<DateTime, Date> {
INSTANCE;
@@ -1278,4 +1374,21 @@ public class MongoTemplateTests {
return source == null ? null : new DateTime(source.getTime());
}
}
public static class MyPerson {
String id;
String name;
Address address;
public String getName() {
return name;
}
}
static class Address {
String state;
String city;
}
}

View File

@@ -15,12 +15,13 @@
*/
package org.springframework.data.mongodb.core;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Pattern;
@@ -31,6 +32,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
@@ -40,6 +42,7 @@ import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@@ -71,11 +74,13 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
DBCollection collection;
MappingMongoConverter converter;
MongoMappingContext mappingContext;
@Before
public void setUp() {
this.converter = new MappingMongoConverter(factory, new MongoMappingContext());
this.mappingContext = new MongoMappingContext();
this.converter = new MappingMongoConverter(factory, mappingContext);
this.template = new MongoTemplate(factory, converter);
when(factory.getDb()).thenReturn(db);
@@ -198,6 +203,29 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
assertThat(entity.id, is(5));
}
/**
* @see DATAMONGO-533
*/
@Test
public void registersDefaultEntityIndexCreatorIfApplicationContextHasOneForDifferentMappingContext() {
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.getBeanFactory().registerSingleton("foo",
new MongoPersistentEntityIndexCreator(new MongoMappingContext(), factory));
MongoTemplate mongoTemplate = new MongoTemplate(factory, converter);
mongoTemplate.setApplicationContext(applicationContext);
Collection<ApplicationListener<?>> listeners = applicationContext.getApplicationListeners();
assertThat(listeners, hasSize(1));
ApplicationListener<?> listener = listeners.iterator().next();
assertThat(listener, is(instanceOf(MongoPersistentEntityIndexCreator.class)));
MongoPersistentEntityIndexCreator creator = (MongoPersistentEntityIndexCreator) listener;
assertThat(creator.isIndexCreatorFor(mappingContext), is(true));
}
class AutogenerateableId {
@Id

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import org.springframework.data.mongodb.core.mapping.Version;
public class PersonWithVersionPropertyOfTypeInteger {
String id;
String firstName;
int age;
@Version
Integer version;
@Override
public String toString() {
return "PersonWithVersionPropertyOfTypeInteger [id=" + id + ", firstName=" + firstName + ", age=" + age
+ ", version=" + version + "]";
}
}

View File

@@ -17,12 +17,13 @@ package org.springframework.data.mongodb.core;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.SerializationUtils.*;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import java.util.Arrays;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

View File

@@ -21,7 +21,7 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration {
@Override
@Bean
public Mongo mongo() throws Exception {
return new Mongo("localhost", 27017);
return new Mongo("127.0.0.1", 27017);
}
@Override

View File

@@ -49,6 +49,7 @@ import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.MappingInstantiationException;
@@ -1252,6 +1253,18 @@ public class MappingMongoConverterUnitTests {
assertThat(values, is(arrayWithSize(2)));
}
/**
* @see DATAMONGO-497
*/
@Test
public void readsEmptyCollectionIntoConstructorCorrectly() {
DBObject source = new BasicDBObject("attributes", new BasicDBList());
TypWithCollectionConstructor result = converter.read(TypWithCollectionConstructor.class, source);
assertThat(result.attributes, is(notNullValue()));
}
private static void assertSyntheticFieldValueOf(Object target, Object expected) {
for (int i = 0; i < 10; i++) {
@@ -1266,6 +1279,37 @@ public class MappingMongoConverterUnitTests {
fail(String.format("Didn't find synthetic field on %s!", target));
}
/**
* @see DATAMGONGO-508
*/
@Test
public void eagerlyReturnsDBRefObjectIfTargetAlreadyIsOne() {
DB db = mock(DB.class);
DBRef dbRef = new DBRef(db, "collection", "id");
org.springframework.data.mongodb.core.mapping.DBRef annotation = mock(org.springframework.data.mongodb.core.mapping.DBRef.class);
assertThat(converter.createDBRef(dbRef, annotation), is(dbRef));
}
/**
* @see DATAMONGO-523
*/
@Test
public void considersTypeAliasAnnotation() {
Aliased aliased = new Aliased();
aliased.name = "foo";
DBObject result = new BasicDBObject();
converter.write(aliased, result);
Object type = result.get("_class");
assertThat(type, is(notNullValue()));
assertThat(type.toString(), is("_"));
}
static class GenericType<T> {
T content;
}
@@ -1440,6 +1484,20 @@ public class MappingMongoConverterUnitTests {
Long innerId;
}
static class TypWithCollectionConstructor {
List<Attribute> attributes;
public TypWithCollectionConstructor(List<Attribute> attributes) {
this.attributes = attributes;
}
}
@TypeAlias("_")
static class Aliased {
String name;
}
private class LocalDateToDateConverter implements Converter<LocalDate, Date> {
public Date convert(LocalDate source) {

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2012 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
* 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,
@@ -17,11 +17,14 @@ package org.springframework.data.mongodb.core.convert;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.DBObjectUtils.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bson.types.ObjectId;
import org.junit.Before;
@@ -31,7 +34,10 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.DBObjectUtils;
import org.springframework.data.mongodb.core.Person;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.query.BasicQuery;
@@ -49,11 +55,11 @@ import com.mongodb.QueryBuilder;
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("unused")
public class QueryMapperUnitTests {
QueryMapper mapper;
MongoMappingContext context;
MappingMongoConverter converter;
@Mock
MongoDbFactory factory;
@@ -63,7 +69,7 @@ public class QueryMapperUnitTests {
context = new MongoMappingContext();
MappingMongoConverter converter = new MappingMongoConverter(factory, context);
converter = new MappingMongoConverter(factory, context);
converter.afterPropertiesSet();
mapper = new QueryMapper(converter);
@@ -200,7 +206,7 @@ public class QueryMapperUnitTests {
}
@Test
public void doesNotHandleNestedFieldsWithDefaultIdNames() {
public void doesHandleNestedFieldsWithDefaultIdNames() {
BasicDBObject dbObject = new BasicDBObject("id", new ObjectId().toString());
dbObject.put("nested", new BasicDBObject("id", new ObjectId().toString()));
@@ -209,7 +215,124 @@ public class QueryMapperUnitTests {
DBObject result = mapper.getMappedObject(dbObject, entity);
assertThat(result.get("_id"), is(instanceOf(ObjectId.class)));
assertThat(((DBObject) result.get("nested")).get("id"), is(instanceOf(String.class)));
assertThat(((DBObject) result.get("nested")).get("_id"), is(instanceOf(ObjectId.class)));
}
/**
* @see DATAMONGO-493
*/
@Test
public void doesNotTranslateNonIdPropertiesFor$NeCriteria() {
ObjectId accidentallyAnObjectId = new ObjectId();
Query query = Query.query(Criteria.where("id").is("id_value").and("publishers")
.ne(accidentallyAnObjectId.toString()));
DBObject dbObject = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(UserEntity.class));
assertThat(dbObject.get("publishers"), is(instanceOf(DBObject.class)));
DBObject publishers = (DBObject) dbObject.get("publishers");
assertThat(publishers.containsField("$ne"), is(true));
assertThat(publishers.get("$ne"), is(instanceOf(String.class)));
}
/**
* @see DATAMONGO-494
*/
@Test
public void usesEntityMetadataInOr() {
Query query = query(new Criteria().orOperator(where("foo").is("bar")));
DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Sample.class));
assertThat(result.keySet(), hasSize(1));
assertThat(result.keySet(), hasItem("$or"));
BasicDBList ors = getAsDBList(result, "$or");
assertThat(ors, hasSize(1));
DBObject criterias = getAsDBObject(ors, 0);
assertThat(criterias.keySet(), hasSize(1));
assertThat(criterias.get("_id"), is(notNullValue()));
assertThat(criterias.get("foo"), is(nullValue()));
}
@Test
public void translatesPropertyReferenceCorrectly() {
Query query = query(where("field").is(new CustomizedField()));
DBObject result = mapper
.getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class));
assertThat(result.containsField("foo"), is(true));
assertThat(result.keySet().size(), is(1));
}
@Test
public void translatesNestedPropertyReferenceCorrectly() {
Query query = query(where("field.field").is(new CustomizedField()));
DBObject result = mapper
.getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class));
assertThat(result.containsField("foo.foo"), is(true));
assertThat(result.keySet().size(), is(1));
}
@Test
public void returnsOriginalKeyIfNoPropertyReference() {
Query query = query(where("bar").is(new CustomizedField()));
DBObject result = mapper
.getMappedObject(query.getQueryObject(), context.getPersistentEntity(CustomizedField.class));
assertThat(result.containsField("bar"), is(true));
assertThat(result.keySet().size(), is(1));
}
@Test
public void convertsAssociationCorrectly() {
Reference reference = new Reference();
reference.id = 5L;
Query query = query(where("reference").is(reference));
DBObject object = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
Object referenceObject = object.get("reference");
assertThat(referenceObject, is(instanceOf(com.mongodb.DBRef.class)));
}
@Test
public void convertsNestedAssociationCorrectly() {
Reference reference = new Reference();
reference.id = 5L;
Query query = query(where("withDbRef.reference").is(reference));
DBObject object = mapper.getMappedObject(query.getQueryObject(),
context.getPersistentEntity(WithDBRefWrapper.class));
Object referenceObject = object.get("withDbRef.reference");
assertThat(referenceObject, is(instanceOf(com.mongodb.DBRef.class)));
}
@Test
public void convertsInKeywordCorrectly() {
Reference first = new Reference();
first.id = 5L;
Reference second = new Reference();
second.id = 6L;
Query query = query(where("reference").in(first, second));
DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
DBObject reference = DBObjectUtils.getAsDBObject(result, "reference");
assertThat(reference.containsField("$in"), is(true));
}
class IdWrapper {
@@ -237,4 +360,31 @@ public class QueryMapperUnitTests {
enum Enum {
INSTANCE;
}
class UserEntity {
String id;
List<String> publishers = new ArrayList<String>();
}
class CustomizedField {
@Field("foo")
CustomizedField field;
}
class WithDBRef {
@DBRef
Reference reference;
}
class Reference {
Long id;
}
class WithDBRefWrapper {
WithDBRef withDbRef;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.index;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Integration tests for {@link MongoPersistentEntityIndexCreator}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MongoPersistentEntityIndexCreatorIntegrationTests {
@Autowired
@Qualifier("mongo1")
MongoOperations templateOne;
@Autowired
@Qualifier("mongo2")
MongoOperations templateTwo;
@After
public void cleanUp() {
templateOne.dropCollection(SampleEntity.class);
templateTwo.dropCollection(SampleEntity.class);
}
@Test
public void createsIndexForConfiguredMappingContextOnly() {
List<IndexInfo> indexInfo = templateOne.indexOps(SampleEntity.class).getIndexInfo();
assertThat(indexInfo, hasSize(greaterThan(0)));
assertThat(indexInfo, Matchers.<IndexInfo> hasItem(hasProperty("name", is("prop"))));
indexInfo = templateTwo.indexOps("sampleEntity").getIndexInfo();
assertThat(indexInfo, hasSize(0));
}
}

View File

@@ -24,9 +24,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mapping.context.MappingContextEvent;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import com.mongodb.DBObject;
@@ -40,6 +44,8 @@ public class MongoPersistentEntityIndexCreatorUnitTests {
@Mock
MongoDbFactory factory;
@Mock
ApplicationContext context;
@Test
public void buildsIndexDefinitionUsingFieldName() {
@@ -55,6 +61,40 @@ public class MongoPersistentEntityIndexCreatorUnitTests {
assertThat(creator.name, is("indexName"));
}
@Test
public void doesNotCreateIndexForEntityComingFromDifferentMappingContext() {
MongoMappingContext mappingContext = new MongoMappingContext();
MongoMappingContext personMappingContext = new MongoMappingContext();
personMappingContext.setInitialEntitySet(Collections.singleton(Person.class));
personMappingContext.initialize();
DummyMongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory);
MongoPersistentEntity<?> entity = personMappingContext.getPersistentEntity(Person.class);
MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty> event = new MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>(
personMappingContext, entity);
creator.onApplicationEvent(event);
assertThat(creator.indexDefinition, is(nullValue()));
}
/**
* @see DATAMONGO-530
*/
@Test
public void isIndexCreatorForMappingContextHandedIntoConstructor() {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.initialize();
MongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory);
assertThat(creator.isIndexCreatorFor(mappingContext), is(true));
assertThat(creator.isIndexCreatorFor(new MongoMappingContext()), is(false));
}
static class Person {
@Indexed(name = "indexName")

View File

@@ -0,0 +1,14 @@
package org.springframework.data.mongodb.core.index;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class SampleEntity {
@Id
String id;
@Indexed
String prop;
}

View File

@@ -16,20 +16,36 @@
package org.springframework.data.mongodb.core.mapping;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.util.ReflectionUtils;
import com.mongodb.DBRef;
/**
* Unit tests for {@link MongoMappingContext}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class MongoMappingContextUnitTests {
@Mock
ApplicationContext applicationContext;
@Test
public void addsSelfReferencingPersistentEntityCorrectly() throws Exception {
@@ -46,6 +62,24 @@ public class MongoMappingContextUnitTests {
context.getPersistentEntity(ClassWithMultipleIdProperties.class);
}
@Test
public void doesNotReturnPersistentEntityForMongoSimpleType() {
MongoMappingContext context = new MongoMappingContext();
assertThat(context.getPersistentEntity(DBRef.class), is(nullValue()));
}
@Test
public void populatesAbstractMappingContextsApplicationCorrectly() {
MongoMappingContext context = new MongoMappingContext();
context.setApplicationContext(applicationContext);
Field field = ReflectionUtils.findField(AbstractMappingContext.class, "applicationContext");
ReflectionUtils.makeAccessible(field);
assertThat(ReflectionUtils.getField(field, context), is(notNullValue()));
}
class ClassWithMultipleIdProperties {
@Id

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 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.
@@ -44,11 +44,9 @@ import com.mongodb.Mongo;
@ContextConfiguration("classpath:infrastructure.xml")
public class GroupByTests {
@Autowired
MongoDbFactory factory;
@Autowired MongoDbFactory factory;
@Autowired
ApplicationContext applicationContext;
@Autowired ApplicationContext applicationContext;
MongoTemplate mongoTemplate;
@@ -158,7 +156,7 @@ public class GroupByTests {
private void assertMapReduceResults(GroupByResults<XObject> results) {
DBObject dboRawResults = results.getRawResults();
String expected = "{ \"serverUsed\" : \"127.0.0.1:27017\" , \"retval\" : [ { \"x\" : 1.0 , \"count\" : 2.0} , { \"x\" : 2.0 , \"count\" : 1.0} , { \"x\" : 3.0 , \"count\" : 3.0}] , \"count\" : 6.0 , \"keys\" : 3 , \"ok\" : 1.0}";
String expected = "{ \"serverUsed\" : \"/127.0.0.1:27017\" , \"retval\" : [ { \"x\" : 1.0 , \"count\" : 2.0} , { \"x\" : 2.0 , \"count\" : 1.0} , { \"x\" : 3.0 , \"count\" : 3.0}] , \"count\" : 6.0 , \"keys\" : 3 , \"ok\" : 1.0}";
Assert.assertEquals(expected, dboRawResults.toString());
int numResults = 0;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,12 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import org.junit.Test;
import org.springframework.data.domain.Sort.Direction;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@@ -51,7 +52,7 @@ public class BasicQueryUnitTests {
BasicQuery query = new BasicQuery("{}");
query.setSortObject(new BasicDBObject("name", -1));
query.sort().on("lastname", Order.ASCENDING);
query.with(new org.springframework.data.domain.Sort(Direction.ASC, "lastname"));
DBObject sortReference = new BasicDBObject("name", -1);
sortReference.put("lastname", 1);

View File

@@ -15,11 +15,11 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.core.query.Criteria;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@@ -58,4 +58,14 @@ public class CriteriaTests {
Criteria c = new Criteria("name").gte("M").and("name").ne("A");
c.getCriteriaObject();
}
@Test
public void equalIfCriteriaMatches() {
Criteria left = new Criteria("name").is("Foo").and("lastname").is("Bar");
Criteria right = new Criteria("name").is("Bar").and("lastname").is("Bar");
assertThat(left, is(not(right)));
assertThat(right, is(not(left)));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,13 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
public class QueryTests {
@@ -100,7 +103,7 @@ public class QueryTests {
public void testComplexQueryWithMultipleChainedCriteria() {
Query q = new Query(where("name").regex("^T.*").and("age").gt(20).lt(80).and("city")
.in("Stockholm", "London", "New York"));
String expected = "{ \"name\" : { \"$regex\" : \"^T.*\" , \"$options\" : \"\"} , \"age\" : { \"$gt\" : 20 , \"$lt\" : 80} , "
String expected = "{ \"name\" : { \"$regex\" : \"^T.*\"} , \"age\" : { \"$gt\" : 20 , \"$lt\" : 80} , "
+ "\"city\" : { \"$in\" : [ \"Stockholm\" , \"London\" , \"New York\"]}}";
Assert.assertEquals(expected, q.getQueryObject().toString());
}
@@ -134,14 +137,37 @@ public class QueryTests {
@Test
public void testQueryWithRegex() {
Query q = new Query(where("name").regex("b.*"));
String expected = "{ \"name\" : { \"$regex\" : \"b.*\" , \"$options\" : \"\"}}";
String expected = "{ \"name\" : { \"$regex\" : \"b.*\"}}";
Assert.assertEquals(expected, q.getQueryObject().toString());
}
@Test
public void testQueryWithRegexandOption() {
public void testQueryWithRegexAndOption() {
Query q = new Query(where("name").regex("b.*", "i"));
String expected = "{ \"name\" : { \"$regex\" : \"b.*\" , \"$options\" : \"i\"}}";
Assert.assertEquals(expected, q.getQueryObject().toString());
}
/**
* @see DATAMONGO-538
*/
@Test
@SuppressWarnings("deprecation")
public void addsDeprecatedSortCorrectly() {
Query query = new Query();
query.sort().on("foo", Order.DESCENDING);
assertThat(query.getSortObject().toString(), is("{ \"foo\" : -1}"));
}
/**
* @see DATAMONGO-538
*/
@Test
public void addsSortCorrectly() {
Query query = new Query().with(new org.springframework.data.domain.Sort(Direction.DESC, "foo"));
assertThat(query.getSortObject().toString(), is("{ \"foo\" : -1}"));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,13 +15,13 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.springframework.data.mongodb.core.query.Order.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.query.Order.*;
import org.junit.Test;
import org.springframework.data.mongodb.core.query.Sort;
@SuppressWarnings("deprecation")
public class SortTests {
@Test

View File

@@ -495,4 +495,32 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
List<Person> result = repository.findByCreatedAtLessThanManually(boyd.createdAt);
assertThat(result.isEmpty(), is(false));
}
}
/**
* @see DATAMONGO-472
*/
@Test
public void findsPeopleUsingNotPredicate() {
List<Person> result = repository.findByLastnameNot("Matthews");
assertThat(result, not(hasItem(dave)));
assertThat(result, hasSize(5));
}
/**
* @see DATAMONGO-521
*/
@Test
public void executesAndQueryCorrectly() {
List<Person> result = repository.findByFirstnameAndLastname("Dave", "Matthews");
assertThat(result, hasSize(1));
assertThat(result, hasItem(dave));
result = repository.findByFirstnameAndLastname("Oliver August", "Matthews");
assertThat(result, hasSize(1));
assertThat(result, hasItem(oliver));
}
}

View File

@@ -106,6 +106,8 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
*/
List<Person> findByFirstnameNotIn(Collection<String> firstnames);
List<Person> findByFirstnameAndLastname(String firstname, String lastname);
/**
* Returns all {@link Person}s with an age between the two given values.
*
@@ -183,4 +185,11 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
*/
List<Person> findByCreatedAtAfter(Date date);
/**
* @see DATAMONGO-472
* @param lastname
* @return
*/
List<Person> findByLastnameNot(String lastname);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2010-2012 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.

View File

@@ -15,11 +15,13 @@
*/
package org.springframework.data.mongodb.repository.query;
import static org.mockito.Mockito.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -27,7 +29,11 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator;
import com.mongodb.BasicDBList;
@@ -76,4 +82,66 @@ public class ConvertingParameterAccessorUnitTests {
assertThat(result, is((Object) reference));
}
/**
* @see DATAMONGO-505
*/
@Test
public void convertsAssociationsToDBRef() {
Property property = new Property();
property.id = 5L;
Object result = setupAndConvert(property);
assertThat(result, is(instanceOf(com.mongodb.DBRef.class)));
com.mongodb.DBRef dbRef = (com.mongodb.DBRef) result;
assertThat(dbRef.getRef(), is("property"));
assertThat(dbRef.getId(), is((Object) 5L));
}
/**
* @see DATAMONGO-505
*/
@Test
public void convertsAssociationsToDBRefForCollections() {
Property property = new Property();
property.id = 5L;
Object result = setupAndConvert(Arrays.asList(property));
assertThat(result, is(instanceOf(Collection.class)));
Collection<?> collection = (Collection<?>) result;
assertThat(collection, hasSize(1));
Object element = collection.iterator().next();
assertThat(element, is(instanceOf(com.mongodb.DBRef.class)));
com.mongodb.DBRef dbRef = (com.mongodb.DBRef) element;
assertThat(dbRef.getRef(), is("property"));
assertThat(dbRef.getId(), is((Object) 5L));
}
private Object setupAndConvert(Object... parameters) {
MongoParameterAccessor delegate = new StubParameterAccessor(parameters);
PotentiallyConvertingIterator iterator = new ConvertingParameterAccessor(converter, delegate).iterator();
MongoPersistentEntity<?> entity = context.getPersistentEntity(Entity.class);
MongoPersistentProperty property = entity.getPersistentProperty("property");
return iterator.nextConverted(property);
}
static class Entity {
@DBRef
Property property;
}
static class Property {
Long id;
}
}

View File

@@ -5,11 +5,11 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:db-factory id="dbFactory" dbname="database" />
<mongo:mapping-converter id="converter" db-factory-ref="dbFactory" />
<mongo:db-factory id="mongoDbFactory" dbname="database" />
<mongo:mapping-converter id="converter" />
<bean class="org.springframework.data.mongodb.gridfs.GridFsTemplate">
<constructor-arg ref="dbFactory" />
<constructor-arg ref="mongoDbFactory" />
<constructor-arg ref="converter" />
</bean>

View File

@@ -1,4 +1,4 @@
log4j.rootCategory=WARN, stdout
log4j.rootCategory=ERROR, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:mapping-converter id="mongoConverter" db-factory-ref="factory1"
base-package="org.springframework.data.mongodb.core.index" />
<bean id="mongo1" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="factory1" />
<constructor-arg ref="mongoConverter" />
</bean>
<bean id="mongo2" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="factory2" />
</bean>
<mongo:db-factory id="factory1" host="127.0.0.1" dbname="mongo-index-db1" />
<mongo:db-factory id="factory2" host="127.0.0.1" dbname="mongo-index-db2" />
</beans>

View File

@@ -52,7 +52,7 @@
<xi:include href="introduction/why-sd-doc.xml"/>
<xi:include href="introduction/requirements.xml"/>
<xi:include href="introduction/getting-started.xml"/>
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/1.4.0.M1/src/docbkx/repositories.xml">
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/1.4.0.RELEASE/src/docbkx/repositories.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" />
</xi:include>
</part>
@@ -72,9 +72,12 @@
<part id="appendix">
<title>Appendix</title>
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.4.0.M1/src/docbkx/repository-namespace-reference.xml">
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.4.0.RELEASE/src/docbkx/repository-namespace-reference.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" />
</xi:include>
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.4.0.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" />
</xi:include>
</part>
</book>

View File

@@ -12,17 +12,17 @@
<title>Knowing Spring</title>
<para>Spring Data uses Spring framework's <ulink
url="http://static.springframework.org/spring/docs/3.0.x/reference/spring-core.html">core</ulink>
url="http://static.springframework.org/spring/docs/3.0.x/reference/html/spring-core.html">core</ulink>
functionality, such as the <ulink
url="http://static.springframework.org/spring/docs/3.0.x/reference/beans.html">IoC</ulink>
url="http://static.springframework.org/spring/docs/3.0.x/reference/html/beans.html">IoC</ulink>
container, <ulink
url="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">type
conv ersion system</ulink>, <ulink
url="http://static.springsource.org/spring/docs/3.0.x/reference/expressions.html">expression
url="http://static.springsource.org/spring/docs/3.0.x/reference/html/validation.html#core-convert">type
conversion system</ulink>, <ulink
url="http://static.springsource.org/spring/docs/3.0.x/reference/html/expressions.html">expression
language</ulink>, <ulink
url="http://static.springsource.org/spring/docs/3.0.x/reference/jmx.html">JMX
url="http://static.springsource.org/spring/docs/3.0.x/reference/html/jmx.html">JMX
integration</ulink>, and portable <ulink
url="http://static.springsource.org/spring/docs/3.0.x/reference/dao.html#dao-exceptions">DAO
url="http://static.springsource.org/spring/docs/3.0.x/reference/html/dao.html#dao-exceptions">DAO
exception hierarchy</ulink>. While it is not important to know the
Spring APIs, understanding the concepts behind them is. At a minimum,
the idea behind IoC should be familiar for whatever IoC container you

View File

@@ -107,15 +107,14 @@
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.data&lt;/groupId&gt;
&lt;artifactId&gt;spring-data-mongodb&lt;/artifactId&gt;
&lt;version&gt;1.0.0.M5&lt;/version&gt;
&lt;version&gt;1.1.0.RELEASE&lt;/version&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
</programlisting>
&lt;/dependencies&gt;</programlisting>
<para>Also change the version of Spring in the pom.xml to be</para>
<programlisting lang="" language="xml">&lt;spring.framework.version&gt;3.0.6.RELEASE&lt;/spring.framework.version&gt;</programlisting>
<programlisting lang="" language="xml">&lt;spring.framework.version&gt;3.1.2.RELEASE&lt;/spring.framework.version&gt;</programlisting>
<para>You will also need to add the location of the Spring Milestone
repository for maven to your pom.xml which is at the same level of your
@@ -125,7 +124,7 @@
&lt;repository&gt;
&lt;id&gt;spring-milestone&lt;/id&gt;
&lt;name&gt;Spring Maven MILESTONE Repository&lt;/name&gt;
&lt;url&gt;http://maven.springframework.org/milestone&lt;/url&gt;
&lt;url&gt;http://repo.springsource.org/libs-milestone&lt;/url&gt;
&lt;/repository&gt;
&lt;/repositories&gt;</programlisting>
@@ -133,8 +132,9 @@
url="http://shrub.appspot.com/maven.springframework.org/milestone/org/springframework/data/">browseable
here</ulink>.</para>
<para>You may also want to set the logging level to DEBUG to see some
additional information, edit the log4j.properties file to have</para>
<para>You may also want to set the logging level to <code>DEBUG</code> to
see some additional information, edit the log4j.properties file to
have</para>
<programlisting>log4j.category.org.springframework.data.document.mongodb=DEBUG
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n</programlisting>
@@ -215,9 +215,10 @@ public class MongoApp {
<itemizedlist>
<listitem>
<para>You can instantiate the central helper class of Spring Mongo,
<link linkend="mongo-template">MongoTemplate</link>, using the
standard <classname>com.mongodb.Mongo</classname> object and the name
of the database to use.</para>
<link
linkend="mongo-template"><classname>MongoTemplate</classname></link>,
using the standard <classname>com.mongodb.Mongo</classname> object and
the name of the database to use.</para>
</listitem>
<listitem>
@@ -241,119 +242,6 @@ public class MongoApp {
stored document, they will be used to instantiate the object</para>
</listitem>
</itemizedlist>
<section id="mongodb-required-jars">
<title>Required Jars</title>
The following jars are required to use Spring Data MongoDB
<itemizedlist>
<listitem>
<para>spring-data-mongodb-1.0.0.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-data-commons-1.2.0.RELEASE.jar</para>
</listitem>
</itemizedlist>
In addition to the above listed Spring Data jars you need to provide the following dependencies:
<itemizedlist>
<listitem>
<para>aopalliance-1.0.0.jar</para>
</listitem>
<listitem>
<para>commons-logging-1.1.1.jar</para>
</listitem>
<listitem>
<para>mongo-java-driver-2.5.3.jar</para>
</listitem>
<listitem>
<para>spring-aop-3.0.7.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-asm-3.0.7.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-beans-3.0.7.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-context-3.0.7.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-core-3.0.7.RELEASE.jar</para>
</listitem>
<listitem>
<para>spring-expression-3.0.7.RELEASE.jar</para>
</listitem>
</itemizedlist>
</section>
<section id="mongo.migrate-m2-m3">
<title>Migrating from M2 to M3</title>
<para>There were several API changes introduced in the M3 release. To
upgrade from M2 to M3 you will need to make. For a full listing of API
changes please refer to this <ulink
url="http://static.springsource.org/spring-data/data-document/docs/jdiff-mongo-m2-m3/mongo-report/">JDiff
Report</ulink>.</para>
<para>The major changes are with respect to MongoTemplate</para>
<itemizedlist>
<listitem>
<para>Constructors have changed on
<classname>MongoTemplate</classname>. <literal>MongoTemplate(Mongo,
String, String)</literal> and <literal>MongoTemplate(Mongo, String,
String, MongoConverter)</literal> were removed.
<literal>MongoTemplate(Mongo, String, UserCredentials),
MongoTemplate(MongoDbFactory), MongoTemplate(MongoDbFactory,
MongoConverter)</literal> were added. These changes will also effect
usage of wiring up <classname>MongoTemplate</classname> in
&lt;bean/&gt; XML defintions.</para>
</listitem>
<listitem>
<para><classname>MongoTemplate</classname> no longer takes a default
collection name. The collection name is now either specified when
the method is invoked or inferred from the Java class, either the
class name or via mapping metadata.</para>
</listitem>
<listitem>
<para>Reordered parameters in some
<classname>MongoTemplate</classname> methods to make signatures more
consistent across the board.</para>
</listitem>
<listitem>
<para>Removed <classname>MongoTemplate</classname> methods that use
<interfacename>MongoReader</interfacename> and
<interfacename>MongoWriter</interfacename>. As an alternative
register a Spring converter with the MappingMongoConverter. See
<link linkend="mapping-explicit-converters">here</link> for
details.</para>
</listitem>
<listitem>
<para>Added <literal>findById</literal> methods to
<classname>MongoTemplate.</classname></para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="mongo.examples-repo">
@@ -544,7 +432,6 @@ public class AppConfig {
DB getDb() throws DataAccessException;
DB getDb(String dbName) throws DataAccessException;
}</programlisting>
<para>The following sections show how you can use the contiainer with
@@ -601,7 +488,6 @@ public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new Mongo(), "database");
}
}</programlisting>
<para>To define the username and password create an instance of
@@ -621,10 +507,7 @@ public class MongoConfiguration {
public @Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}
</programlisting>
<para/>
}</programlisting>
</section>
<section id="mongo.mongo-db-factory-xml">
@@ -685,8 +568,6 @@ public class MongoConfiguration {
&lt;bean id="anotherMongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"&gt;
&lt;constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/&gt;
&lt;/bean&gt;</programlisting>
<para/>
</section>
</section>
@@ -2731,4 +2612,147 @@ mongoTemplate.dropCollection("MyNewCollection"); </programlisting>
}
});</programlisting>
</section>
<section id="gridfs">
<title>GridFS support</title>
<para>MongoDB supports storing binary files inside it's filesystem GridFS.
Spring Data MongoDB provides a
<interfacename>GridFsOperations</interfacename> interface as well as the
according implementation <classname>GridFsTemplate</classname> to easily
interact with the filesystem. You can setup a
<classname>GridFsTemplate</classname> instance by handing it a
<interfacename>MongoDbFactory</interfacename> as well as a
<interfacename>MongoConverter</interfacename>:</para>
<example>
<title>JavaConfig setup for a GridFsTemplate</title>
<programlisting language="java">class GridFsConfiguration extends AbstractMongoConfiguration {
// … further configuration omitted
@Bean
public GridFsTemplate gridFsTemplate() {
return new GridFsTemplate(mongoDbFactory(), mappingMongoConverter());
}
}</programlisting>
</example>
<para>An according XML configuration looks like this:</para>
<example>
<title>XML configuration for a GridFsTemplate</title>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;
&lt;mongo:db-factory id="mongoDbFactory" dbname="database" /&gt;
&lt;mongo:mapping-converter id="converter" /&gt;
&lt;bean class="org.springframework.data.mongodb.gridfs.GridFsTemplate"&gt;
&lt;constructor-arg ref="mongoDbFactory" /&gt;
&lt;constructor-arg ref="converter" /&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</example>
<para>You can no get the template injected and perform storing and
retrieving operations to it.</para>
<example>
<title>Using GridFsTemplate to store files</title>
<programlisting language="java">class GridFsClient {
@Autowired
GridFsOperations operations;
@Test
public void storeFileToGridFs {
FileMetadata metadata = new FileMetadata();
// populate metadata
Resource file = … // lookup File or Resource
operations.store(file.getInputStream(), "filename.txt", metadata);
}
}</programlisting>
</example>
<para>The <methodname>store(…)</methodname> operations take an
<interfacename>InputStream</interfacename>, a filename and optionally
metadata information about the file to store. The metadata can be an
arbitrary object which will be marshalled by the
<interfacename>MongoConverter</interfacename> configured with the
<classname>GridFsTemplate</classname>. Alternatively you can also provide
a <interfacename>DBObject</interfacename> as well.</para>
<para>Reading files from the filesystem can either be achieved through the
<methodname>find(…)</methodname> or
<methodname>getResources(…)</methodname> methods. Let's have a look at the
<methodname>find(…)</methodname> methods first. You can either find a
single file matching a <classname>Query</classname> or multiple ones. To
easily define file queries we provide the
<classname>GridFsCriteria</classname> helper class. It provides static
factory methods to encapsulate default metadata fields (e.g.
<methodname>whereFilename()</methodname>,
<methodname>whereContentType()</methodname>) or the custom one through
<methodname>whereMetaData()</methodname>.</para>
<example>
<title>Using GridFsTemplate to query for files</title>
<programlisting language="java">class GridFsClient {
@Autowired
GridFsOperations operations;
@Test
public void findFilesInGridFs {
List&lt;GridFSDBFile&gt; result = operations.find(query(whereFilename().is("filename.txt")))
}
}</programlisting>
</example>
<note>
<para>Currently MongoDB does not support defining sort criterias when
retrieving files from GridFS. Thus any sort criterias defined on the
<classname>Query</classname> instance handed into the
<methodname>find(…)</methodname> method will be disregarded.</para>
</note>
<para>The other option to read files from the GridFs is using the methods
introduced by the <interfacename>ResourcePatternResolver</interfacename>
interface. They allow handing an Ant path into the method ar thus retrieve
files matching the given pattern.</para>
<example>
<title>Using GridFsTemplate to read files</title>
<programlisting language="java">class GridFsClient {
@Autowired
GridFsOperations operations;
@Test
public void readFilesFromGridFs {
GridFsResources[] txtFiles = operations.getResources("*.txt");
}
}</programlisting>
</example>
<para><interfacename>GridFsOperations</interfacename> extending
<interfacename>ResourcePatternResolver</interfacename> allows the
<classname>GridFsTemplate</classname> e.g. to be plugged into an
<interfacename>ApplicationContext</interfacename> to read Spring Config
files from a MongoDB.</para>
</section>
</chapter>

View File

@@ -1,6 +1,76 @@
Spring Data MongoDB Changelog
=============================================
Changes in version 1.1.0.GA (2012-10-10)
----------------------------------------
** Bug
* [DATAMONGO-523] - @TypeAlias annotation not used with AbstractMongoConfiguration
* [DATAMONGO-527] - Criteria.equals(…) broken for complex criterias
* [DATAMONGO-530] - MongoMappingContext.setApplicationContext(…) does not invoke superclass method
* [DATAMONGO-531] - StackOverflowError when persisting Groovy beans
* [DATAMONGO-532] - Multithreading authentication issue
* [DATAMONGO-533] - Default MongoPersistentEntityIndexCreator not registered if ApplicationContext already contains one for different MappingContext
* [DATAMONGO-535] - Retrieve of existing Mongo DB from Transaction is not working
* [DATAMONGO-539] - Document remove doesn't work when giving collection name as a parameter
** Improvement
* [DATAMONGO-279] - Optimistic locking using @Version field
* [DATAMONGO-456] - XSD incorrectly states the default value for the mongo-ref attribute of the mongo:db-factory configuration element
* [DATAMONGO-457] - broken links "Spring Data MongoDB - Reference Documentation"
* [DATAMONGO-526] - Polish README.md
* [DATAMONGO-529] - Improve Querydsl setup
* [DATAMONGO-538] - Unify usage of Sort APIs in Query API
** New Feature
* [DATAMONGO-389] - stable release spring-data-mongodb should work with stable spring spring-data-jpa
** Task
* [DATAMONGO-484] - Migrate to latest MongoDB Java driver
* [DATAMONGO-528] - Document GridFS support
* [DATAMONGO-536] - Fix package cycle introduced by SerializationUtils
* [DATAMONGO-541] - Release 1.1 GA
* [DATAMONGO-543] - Polish reference documentation
* [DATAMONGO-548] - Upgrade to Querydsl 2.8.0
Changes in version 1.1.0.RC1 (2012-24-08)
-----------------------------------------
** Bug
* [DATAMONGO-493] - Criteria.ne() method converts all value into ObjectId
* [DATAMONGO-494] - $or/$nor expressions do not consider entity class mapping
* [DATAMONGO-495] - JSON can't serialize Enum when printing Query in DEBUG message
* [DATAMONGO-497] - Reading an empty List throws a MappingInstantiationException because it returns an HashSet instead of returning an ArrayList
* [DATAMONGO-505] - Conversion of associations doesn't work for collection values
* [DATAMONGO-508] - DBRef can accidentally get added as PersistentProperty
* [DATAMONGO-517] - QueryMapping incorrectly translates complex keywords
** Improvement
* [DATAMONGO-496] - AbstractMongoConfiguration.getMappingBasePackage() could default to config class' package
* [DATAMONGO-499] - Namespace XSDs of current release version should refer to repositories XSD in version 1.0
* [DATAMONGO-500] - Index creation reacts on events not intended for it
* [DATAMONGO-502] - QueryMapper should transparently translate property names to field names
* [DATAMONGO-509] - SimpleMongoRepository.exists(…) can be improved.
* [DATAMONGO-510] - Criteria should only use BasicDBList internally
* [DATAMONGO-511] - QueryMapper should correctly transform associations
* [DATAMONGO-516] - Make Spring 3.1.2.RELEASE default Spring dependency version
** Task
* [DATAMONGO-513] - Release 1.1 RC1
Changes in version 1.0.4.RELEASE MongoDB (2012-08-24)
-----------------------------------------------------
** Bug
* [DATAMONGO-493] - Criteria.ne() method converts all value into ObjectId
* [DATAMONGO-494] - $or/$nor expressions do not consider entity class mapping
* [DATAMONGO-495] - JSON can't serialize Enum when printing Query in DEBUG message
** Improvement
* [DATAMONGO-499] - Namespace XSDs of current release version should refer to repositories XSD in version 1.0
** Task
* [DATAMONGO-514] - Release 1.0.4.
Changes in version 1.1.0.M2 (2012-24-07)
----------------------------------------
** Bug