Compare commits

...

21 Commits

Author SHA1 Message Date
Spring Buildmaster
a8fad84514 DATAMONGO-608 - Prepare next development iteration. 2013-02-08 03:50:36 -08:00
Spring Buildmaster
43d9f2f948 DATAMONGO-608 - Release version 1.1.2.RELEASE. 2013-02-08 03:50:29 -08:00
Oliver Gierke
fbb281959b DATAMONGO-608 - Upgraded to Spring Data Commons 1.4.1. 2013-02-08 12:20:54 +01:00
Oliver Gierke
c9ff78d17b DATACMNS-263 - Upgraded to Mongo Java Driver 2.9.3. 2013-02-08 12:19:43 +01:00
Oliver Gierke
b6f5614573 DATAMONGO-608 - Updated changelog. 2013-02-08 12:02:22 +01:00
Michal Vich
3c43a43206 DATAMONGO-81 - Added more unit tests for MongoExceptionTranslator. 2013-02-06 15:21:14 +01:00
Michal Vich
b2f82bb5bf DATAMONGO-568 - MongoTemplate.find(…) does not throw NullPointerException anymore.
Trigger findAll(…) if the Query object given to a find(…) method is null.
2013-02-06 15:20:57 +01:00
Oliver Gierke
38ccc59137 DATAMONGO-601 - Prevent password from being logged in case of an exception. 2013-01-29 16:47:22 +01:00
Oliver Gierke
cfa3e467d1 DATAMONGO-600 - Fixed parameter binding for derived queries on properties using polymorphism.
We need to retain the type in the serialized DBObject in case a derived query binds parameters for properties that use polymorphism as we serialize the object as nested document and this only matches in an all-or-nothing way. So if the type information is missing, we won't see any results.

So we now hand the TypeInformation of the property into the conversion logic and transparently skip the type information removal in case the types differ. Upgraded to Querydsl 2.8.2 as it fixes a bug regarding the APT processing which the test cases would stumble into otherwise.
2013-01-25 11:56:04 +01:00
Philipp Schneider
138a4942e9 DATAMONGO-583 - Using while (…) instead of for (…) for DBCursors to avoid memory leak.
Instead of iterating over the DBCursor using a for-loop we now use a while-loop to avoid the potential memory leak outlined in [0].

[0] https://jira.mongodb.org/browse/JAVA-664
2012-12-13 12:07:42 +05:30
Oliver Gierke
a110197b15 DATAMONGO-590 - Code cleanups in MongoTemplate and error handling APIs. 2012-12-13 12:07:33 +05:30
Oliver Gierke
0745fe1e25 DATAMONGO-588 - Version attribute now gets initialized on insert.
The version attribute of an entity has not been correctly initialized to 0 when inserting objects using MongoTemplate.insert(…). We now set it to 0 correctly.
2012-12-10 17:38:58 +09:00
Oliver Gierke
e16d6f4529 DATAMONGO-585 - Fix concurrency issue in database authentication.
So far the authentication of the database was synchronized *after* the check whether the database under consideration had already been authenticated. This can cause threads to concurrently try to authenticate the database which is rejected by the driver. Improved the synchronization block to include both the ….isAuthenticated() check as well as the authentication.
2012-12-03 11:48:04 +01:00
Oliver Gierke
fa1cc5011b DATAMONGO-580 - Improved BeanDefinitionParser for MappingMongoConverter. 2012-11-27 14:56:09 +01:00
Oliver Gierke
90d146235c DATAMONGO-578 - Fixed Maven version in parent pom.xml. 2012-11-23 19:19:26 +01:00
Oliver Gierke
23e1ebc000 DATAMONGO-576 - Configure java.util.logging to prevent verbose test logging.
Added Slf4j bridge and configured surefire to configure JUL accordingly.
2012-11-23 10:50:40 +01:00
Oliver Gierke
8850c2caf5 DATAMONGO-575 - Improved implementation of entity metadata lookup in MongoQueryMethod.
Got rid of obsolete EntityInformationCreator API and moved to a custom EntityMetadata extension instead.
2012-11-23 10:02:43 +01:00
Oliver Gierke
49d874d984 DATAMONGO-570 - Guard against null values in references.
QueryMapper does not try to convert null values into DBRef objects anymore but returns the plain null value as is.
2012-11-13 18:27:51 +01:00
Oliver Gierke
6fc1b7c1f0 DATAMONGO-573 - Moved to Logback for test logging. 2012-11-13 17:50:27 +01:00
Oliver Gierke
eb7c0fe1dd DATAMONGO-559 - Prepare 1.1.x branch.
Set version number to 1.1.2.BUILD-SNAPSHOT. Upgraded to Spring Data Commons 1.4.1.BUILD-SNAPSHOT.
2012-11-13 16:53:52 +01:00
Oliver Gierke
55dc16d8fa DATAMONGO-563 - Upgraded MongoDB Java driver to 2.9.2. 2012-10-24 22:43:45 +02:00
49 changed files with 1036 additions and 491 deletions

View File

@@ -6,7 +6,7 @@
<name>Spring Data MongoDB Distribution</name> <name>Spring Data MongoDB Distribution</name>
<description>Spring Data project for MongoDB</description> <description>Spring Data project for MongoDB</description>
<url>http://www.springsource.org/spring-data/mongodb</url> <url>http://www.springsource.org/spring-data/mongodb</url>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>spring-data-mongodb</module> <module>spring-data-mongodb</module>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId> <artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath> <relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent> </parent>
<artifactId>spring-data-mongodb-cross-store</artifactId> <artifactId>spring-data-mongodb-cross-store</artifactId>
@@ -42,7 +42,7 @@
<dependency> <dependency>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId> <artifactId>spring-data-mongodb</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -1,12 +0,0 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
log4j.category.org.springframework=INFO
log4j.category.org.springframework.data=TRACE
log4j.category.org.hibernate.SQL=DEBUG
# for debugging datasource initialization
# log4j.category.test.jdbc=DEBUG

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<!--
<logger name="org.springframework" level="debug" />
-->
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -4,12 +4,16 @@
<parent> <parent>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId> <artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath> <relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent> </parent>
<artifactId>spring-data-mongodb-log4j</artifactId> <artifactId>spring-data-mongodb-log4j</artifactId>
<name>Spring Data MongoDB Log4J Appender</name> <name>Spring Data MongoDB Log4J Appender</name>
<properties>
<log4j.version>1.2.16</log4j.version>
</properties>
<dependencies> <dependencies>
<!-- MongoDB --> <!-- MongoDB -->

View File

@@ -6,7 +6,7 @@
<name>Spring Data MongoDB Parent</name> <name>Spring Data MongoDB Parent</name>
<description>Spring Data project for MongoDB</description> <description>Spring Data project for MongoDB</description>
<url>http://www.springsource.org/spring-data/mongodb</url> <url>http://www.springsource.org/spring-data/mongodb</url>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<developers> <developers>
@@ -84,15 +84,15 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- versions for commonly-used dependencies --> <!-- versions for commonly-used dependencies -->
<mongo.version>2.9.1</mongo.version> <mongo.version>2.9.3</mongo.version>
<junit.version>4.10</junit.version> <junit.version>4.10</junit.version>
<log4j.version>1.2.16</log4j.version> <logback.version>1.0.6</logback.version>
<org.mockito.version>1.9.0</org.mockito.version> <org.mockito.version>1.9.0</org.mockito.version>
<org.slf4j.version>1.6.1</org.slf4j.version> <org.slf4j.version>1.6.1</org.slf4j.version>
<org.codehaus.jackson.version>1.6.1</org.codehaus.jackson.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.30>3.0.7.RELEASE</org.springframework.version.30>
<org.springframework.version.range>3.1.2.RELEASE</org.springframework.version.range> <org.springframework.version.range>3.1.2.RELEASE</org.springframework.version.range>
<data.commons.version>1.4.0.RELEASE</data.commons.version> <data.commons.version>1.4.1.RELEASE</data.commons.version>
<aspectj.version>1.6.11.RELEASE</aspectj.version> <aspectj.version>1.6.11.RELEASE</aspectj.version>
<bundlor.failOnWarnings>true</bundlor.failOnWarnings> <bundlor.failOnWarnings>true</bundlor.failOnWarnings>
</properties> </properties>
@@ -163,14 +163,14 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>jul-to-slf4j</artifactId>
<version>${org.slf4j.version}</version> <version>${org.slf4j.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>log4j</artifactId> <artifactId>logback-classic</artifactId>
<version>${log4j.version}</version> <version>${logback.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -265,6 +265,9 @@
<exclude>**/PerformanceTests.java</exclude> <exclude>**/PerformanceTests.java</exclude>
</excludes> </excludes>
<junitArtifactName>junit:junit-dep</junitArtifactName> <junitArtifactName>junit:junit-dep</junitArtifactName>
<systemPropertyVariables>
<java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
</systemPropertyVariables>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@@ -326,8 +329,8 @@
</pluginRepositories> </pluginRepositories>
<repositories> <repositories>
<repository> <repository>
<id>spring-libs-release</id> <id>spring-libs-snapshot</id>
<url>http://repo.springsource.org/libs-release</url> <url>http://repo.springsource.org/libs-snapshot</url>
</repository> </repository>
</repositories> </repositories>
<reporting> <reporting>

View File

@@ -4,14 +4,14 @@
<parent> <parent>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId> <artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version> <version>1.1.3.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-mongodb-parent/pom.xml</relativePath> <relativePath>../spring-data-mongodb-parent/pom.xml</relativePath>
</parent> </parent>
<artifactId>spring-data-mongodb</artifactId> <artifactId>spring-data-mongodb</artifactId>
<name>Spring Data MongoDB</name> <name>Spring Data MongoDB</name>
<properties> <properties>
<querydsl.version>2.8.0</querydsl.version> <querydsl.version>2.8.2</querydsl.version>
<cdi.version>1.0</cdi.version> <cdi.version>1.0</cdi.version>
<validation.version>1.0.0.GA</validation.version> <validation.version>1.0.0.GA</validation.version>
<webbeans.version>1.1.3</webbeans.version> <webbeans.version>1.1.3</webbeans.version>
@@ -64,12 +64,6 @@
<groupId>org.mongodb</groupId> <groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId> <artifactId>mongo-java-driver</artifactId>
<version>${mongo.version}</version> <version>${mongo.version}</version>
<exclusions>
<exclusion>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -26,4 +26,6 @@ public abstract class BeanNames {
static final String MONGO = "mongo"; static final String MONGO = "mongo";
static final String DB_FACTORY = "mongoDbFactory"; static final String DB_FACTORY = "mongoDbFactory";
static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener"; static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener";
static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory";
static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter";
} }

View File

@@ -24,12 +24,12 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -38,6 +38,7 @@ import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
@@ -68,25 +69,26 @@ import org.w3c.dom.Element;
* @author Oliver Gierke * @author Oliver Gierke
* @author Maciej Walkowiak * @author Maciej Walkowiak
*/ */
public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { public class MappingMongoConverterParser implements BeanDefinitionParser {
private static final String BASE_PACKAGE = "base-package"; private static final String BASE_PACKAGE = "base-package";
private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator", private static final boolean jsr303Present = ClassUtils.isPresent("javax.validation.Validator",
MappingMongoConverterParser.class.getClassLoader()); MappingMongoConverterParser.class.getClassLoader());
@Override /* (non-Javadoc)
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
throws BeanDefinitionStoreException { */
String id = super.resolveId(element, definition, parserContext); public BeanDefinition parse(Element element, ParserContext parserContext) {
return StringUtils.hasText(id) ? id : "mappingConverter";
}
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinitionRegistry registry = parserContext.getRegistry();
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
id = StringUtils.hasText(id) ? id : "mappingConverter";
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext); BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext);
String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition); String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition, id);
// Need a reference to a Mongo instance // Need a reference to a Mongo instance
String dbFactoryRef = element.getAttribute("db-factory-ref"); String dbFactoryRef = element.getAttribute("db-factory-ref");
@@ -111,18 +113,23 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
} }
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class); .genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(ctxRef)); indexHelperBuilder.addConstructorArgReference(ctxRef);
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(dbFactoryRef)); indexHelperBuilder.addConstructorArgReference(dbFactoryRef);
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
INDEX_HELPER));
} }
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext); BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
if (validatingMongoEventListener != null) { if (validatingMongoEventListener != null) {
registry.registerBeanDefinition(VALIDATING_EVENT_LISTENER, validatingMongoEventListener); parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
VALIDATING_EVENT_LISTENER));
} }
return converterBuilder.getBeanDefinition(); parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
parserContext.popAndRegisterContainingComponent();
return null;
} }
private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) { private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) {
@@ -136,7 +143,6 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
RuntimeBeanReference validator = getValidator(builder, parserContext); RuntimeBeanReference validator = getValidator(builder, parserContext);
if (validator != null) { if (validator != null) {
builder.getRawBeanDefinition().setBeanClass(ValidatingMongoEventListener.class); builder.getRawBeanDefinition().setBeanClass(ValidatingMongoEventListener.class);
builder.addConstructorArgValue(validator); builder.addConstructorArgValue(validator);
@@ -158,13 +164,13 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
validatorDef.setSource(source); validatorDef.setSource(source);
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); parserContext.registerBeanComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName); return new RuntimeBeanReference(validatorName);
} }
private String potentiallyCreateMappingContext(Element element, ParserContext parserContext, static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
BeanDefinition conversionsDefinition) { BeanDefinition conversionsDefinition, String converterId) {
String ctxRef = element.getAttribute("mapping-context-ref"); String ctxRef = element.getAttribute("mapping-context-ref");
@@ -191,11 +197,9 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition); mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
} }
parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition()); ctxRef = converterId + "." + MAPPING_CONTEXT;
ctxRef = MAPPING_CONTEXT;
parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef)); parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
return ctxRef; return ctxRef;
} }
@@ -233,7 +237,7 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition(); AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
conversionsBean.setSource(parserContext.extractSource(element)); conversionsBean.setSource(parserContext.extractSource(element));
parserContext.getRegistry().registerBeanDefinition("customConversions", conversionsBean); parserContext.registerBeanComponent(new BeanComponentDefinition(conversionsBean, "customConversions"));
return conversionsBean; return conversionsBean;
} }
@@ -241,7 +245,7 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
return null; return null;
} }
public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) { public static Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {
String basePackage = element.getAttribute(BASE_PACKAGE); String basePackage = element.getAttribute(BASE_PACKAGE);

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,59 +13,53 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.data.mongodb.core; package org.springframework.data.mongodb.core;
import org.springframework.util.Assert;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.WriteConcern; import com.mongodb.WriteConcern;
/** /**
* Represents an action taken against the collection. Used by {@link WriteConcernResolver} to determine a custom * Represents an action taken against the collection. Used by {@link WriteConcernResolver} to determine a custom
* WriteConcern based on this information. * {@link WriteConcern} based on this information.
*
* Properties that will always be not-null are collectionName and defaultWriteConcern. The EntityClass is null only for
* the MongoActionOperaton.INSERT_LIST.
*
* <ul> * <ul>
* <li>INSERT, SAVE have null query</li> * <li>INSERT, SAVE have null query</li>
* <li>REMOVE has null document</li> * <li>REMOVE has null document</li>
* <li>INSERT_LIST has null entityClass, document, and query</li> * <li>INSERT_LIST has null entityType, document, and query</li>
* </ul> * </ul>
* *
* @author Mark Pollack * @author Mark Pollack
* * @author Oliver Gierke
*/ */
public class MongoAction { public class MongoAction {
private String collectionName; private final String collectionName;
private final WriteConcern defaultWriteConcern;
private WriteConcern defaultWriteConcern; private final Class<?> entityType;
private final MongoActionOperation mongoActionOperation;
private Class<?> entityClass; private final DBObject query;
private final DBObject document;
private MongoActionOperation mongoActionOperation;
private DBObject query;
private DBObject document;
/** /**
* Create an instance of a MongoAction * Create an instance of a {@link MongoAction}.
* *
* @param defaultWriteConcern the default write concern * @param defaultWriteConcern the default write concern.
* @param mongoActionOperation action being taken against the collection * @param mongoActionOperation action being taken against the collection
* @param collectionName the collection name * @param collectionName the collection name, must not be {@literal null} or empty.
* @param entityClass the POJO that is being operated against * @param entityType the POJO that is being operated against
* @param document the converted DBObject from the POJO or Spring Update object * @param document the converted DBObject from the POJO or Spring Update object
* @param query the converted DBOjbect from the Spring Query object * @param query the converted DBOjbect from the Spring Query object
*/ */
public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation, public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation,
String collectionName, Class<?> entityClass, DBObject document, DBObject query) { String collectionName, Class<?> entityType, DBObject document, DBObject query) {
super();
Assert.hasText(collectionName, "Collection name must not be null or empty!");
this.defaultWriteConcern = defaultWriteConcern; this.defaultWriteConcern = defaultWriteConcern;
this.mongoActionOperation = mongoActionOperation; this.mongoActionOperation = mongoActionOperation;
this.collectionName = collectionName; this.collectionName = collectionName;
this.entityClass = entityClass; this.entityType = entityType;
this.query = query; this.query = query;
this.document = document; this.document = document;
} }
@@ -78,8 +72,16 @@ public class MongoAction {
return defaultWriteConcern; return defaultWriteConcern;
} }
/**
* @deprecated use {@link #getEntityType()} instead.
*/
@Deprecated
public Class<?> getEntityClass() { public Class<?> getEntityClass() {
return entityClass; return entityType;
}
public Class<?> getEntityType() {
return entityType;
} }
public MongoActionOperation getMongoActionOperation() { public MongoActionOperation getMongoActionOperation() {

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ package org.springframework.data.mongodb.core;
* for a given mutating operation * for a given mutating operation
* *
* @author Mark Pollack * @author Mark Pollack
* @author Oliver Gierke
* @see MongoAction * @see MongoAction
*
*/ */
public enum MongoActionOperation { public enum MongoActionOperation {

View File

@@ -104,15 +104,16 @@ public abstract class MongoDbUtils {
DB db = mongo.getDB(databaseName); DB db = mongo.getDB(databaseName);
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword(); boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
if (credentialsGiven && !db.isAuthenticated()) { synchronized (db) {
String username = credentials.getUsername(); if (credentialsGiven && !db.isAuthenticated()) {
String password = credentials.hasPassword() ? credentials.getPassword() : null;
String username = credentials.getUsername();
String password = credentials.hasPassword() ? credentials.getPassword() : null;
synchronized (db) {
if (!db.authenticate(username, password == null ? null : password.toCharArray())) { if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName
+ "], username = [" + username + "], password = [" + password + "]", databaseName, credentials); + "], username = [" + username + "], password = [ -not-shown- ]", databaseName, credentials);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2011 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,12 +15,6 @@
*/ */
package org.springframework.data.mongodb.core; package org.springframework.data.mongodb.core;
import com.mongodb.MongoException;
import com.mongodb.MongoException.CursorNotFound;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
import com.mongodb.MongoInternalException;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.DuplicateKeyException;
@@ -29,21 +23,26 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.UncategorizedMongoDbException; import org.springframework.data.mongodb.UncategorizedMongoDbException;
import com.mongodb.MongoException;
import com.mongodb.MongoException.CursorNotFound;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
import com.mongodb.MongoInternalException;
/** /**
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate * Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
* exception from the {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation is * exception from the {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation is
* appropriate: any other exception may have resulted from user code, and should not be translated. * appropriate: any other exception may have resulted from user code, and should not be translated.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Michal Vich
*/ */
public class MongoExceptionTranslator implements PersistenceExceptionTranslator { public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
/* /*
* (non-Javadoc) * (non-Javadoc)
* * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
* @see org.springframework.dao.support.PersistenceExceptionTranslator# */
* translateExceptionIfPossible(java.lang.RuntimeException)
*/
public DataAccessException translateExceptionIfPossible(RuntimeException ex) { public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
// Check for well-known MongoException subclasses. // Check for well-known MongoException subclasses.
@@ -52,14 +51,23 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
if (ex instanceof DuplicateKey) { if (ex instanceof DuplicateKey) {
return new DuplicateKeyException(ex.getMessage(), ex); return new DuplicateKeyException(ex.getMessage(), ex);
} }
if (ex instanceof Network) { if (ex instanceof Network) {
return new DataAccessResourceFailureException(ex.getMessage(), ex); return new DataAccessResourceFailureException(ex.getMessage(), ex);
} }
if (ex instanceof CursorNotFound) { if (ex instanceof CursorNotFound) {
return new DataAccessResourceFailureException(ex.getMessage(), ex); return new DataAccessResourceFailureException(ex.getMessage(), ex);
} }
if (ex instanceof MongoInternalException) {
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
}
if (ex instanceof MongoException) { if (ex instanceof MongoException) {
int code = ((MongoException) ex).getCode(); int code = ((MongoException) ex).getCode();
if (code == 11000 || code == 11001) { if (code == 11000 || code == 11001) {
throw new DuplicateKeyException(ex.getMessage(), ex); throw new DuplicateKeyException(ex.getMessage(), ex);
} else if (code == 12000 || code == 13440) { } else if (code == 12000 || code == 13440) {
@@ -69,9 +77,6 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
} }
return new UncategorizedMongoDbException(ex.getMessage(), ex); return new UncategorizedMongoDbException(ex.getMessage(), ex);
} }
if (ex instanceof MongoInternalException) {
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
}
// If we get here, we have an exception that resulted from user code, // If we get here, we have an exception that resulted from user code,
// rather than the persistence provider, so we return null to indicate // rather than the persistence provider, so we return null to indicate

View File

@@ -116,7 +116,7 @@ import com.mongodb.util.JSONParseException;
public class MongoTemplate implements MongoOperations, ApplicationContextAware { public class MongoTemplate implements MongoOperations, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class); private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class);
private static final String ID = "_id"; private static final String ID_FIELD = "_id";
private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE; private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE;
private static final Collection<String> ITERABLE_CLASSES; private static final Collection<String> ITERABLE_CLASSES;
@@ -130,32 +130,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses); ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses);
} }
/*
* WriteConcern to be used for write operations if it has been specified.
* Otherwise we should not use a WriteConcern defaulting to the one set for
* the DB or Collection.
*/
private WriteConcern writeConcern = null;
private WriteConcernResolver writeConcernResolver = new DefaultWriteConcernResolver();
/*
* WriteResultChecking to be used for write operations if it has been
* specified. Otherwise we should not do any checking.
*/
private WriteResultChecking writeResultChecking = WriteResultChecking.NONE;
/**
* Set the ReadPreference when operating on a collection. See {@link #prepareCollection(DBCollection)}
*/
private ReadPreference readPreference = null;
private final MongoConverter mongoConverter; private final MongoConverter mongoConverter;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext; private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private final MongoDbFactory mongoDbFactory; private final MongoDbFactory mongoDbFactory;
private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator(); private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
private final QueryMapper mapper; private final QueryMapper mapper;
private WriteConcern writeConcern;
private WriteConcernResolver writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
private WriteResultChecking writeResultChecking = WriteResultChecking.NONE;
private ReadPreference readPreference;
private ApplicationEventPublisher eventPublisher; private ApplicationEventPublisher eventPublisher;
private ResourceLoader resourceLoader; private ResourceLoader resourceLoader;
private MongoPersistentEntityIndexCreator indexCreator; private MongoPersistentEntityIndexCreator indexCreator;
@@ -163,8 +147,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a basic template configuration * Constructor used for a basic template configuration
* *
* @param mongo * @param mongo must not be {@literal null}.
* @param databaseName * @param databaseName must not be {@literal null} or empty.
*/ */
public MongoTemplate(Mongo mongo, String databaseName) { public MongoTemplate(Mongo mongo, String databaseName) {
this(new SimpleMongoDbFactory(mongo, databaseName), null); this(new SimpleMongoDbFactory(mongo, databaseName), null);
@@ -174,8 +158,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Constructor used for a template configuration with user credentials in the form of * Constructor used for a template configuration with user credentials in the form of
* {@link org.springframework.data.authentication.UserCredentials} * {@link org.springframework.data.authentication.UserCredentials}
* *
* @param mongo * @param mongo must not be {@literal null}.
* @param databaseName * @param databaseName must not be {@literal null} or empty.
* @param userCredentials * @param userCredentials
*/ */
public MongoTemplate(Mongo mongo, String databaseName, UserCredentials userCredentials) { public MongoTemplate(Mongo mongo, String databaseName, UserCredentials userCredentials) {
@@ -183,9 +167,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
/** /**
* Constructor used for a basic template configuration * Constructor used for a basic template configuration.
* *
* @param mongoDbFactory * @param mongoDbFactory must not be {@literal null}.
*/ */
public MongoTemplate(MongoDbFactory mongoDbFactory) { public MongoTemplate(MongoDbFactory mongoDbFactory) {
this(mongoDbFactory, null); this(mongoDbFactory, null);
@@ -194,7 +178,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/** /**
* Constructor used for a basic template configuration. * Constructor used for a basic template configuration.
* *
* @param mongoDbFactory * @param mongoDbFactory must not be {@literal null}.
* @param mongoConverter * @param mongoConverter
*/ */
public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) { public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) {
@@ -228,7 +212,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
/** /**
* Configures the {@link WriteConcern} to be used with the template. * Configures the {@link WriteConcern} to be used with the template. If none is configured the {@link WriteConcern}
* configured on the {@link MongoDbFactory} will apply. If you configured a {@link Mongo} instance no
* {@link WriteConcern} will be used.
* *
* @param writeConcern * @param writeConcern
*/ */
@@ -276,7 +262,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get * 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. * created appropriately for entity types persisted through this {@link MongoTemplate} instance.
* *
* @param context * @param context must not be {@literal null}.
*/ */
private void prepareIndexCreator(ApplicationContext context) { private void prepareIndexCreator(ApplicationContext context) {
@@ -501,8 +487,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
public <T> List<T> find(final Query query, Class<T> entityClass, String collectionName) { public <T> List<T> find(final Query query, Class<T> entityClass, String collectionName) {
CursorPreparer cursorPreparer = query == null ? null : new QueryCursorPreparer(query);
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass, cursorPreparer); if (query == null) {
return findAll(entityClass, collectionName);
}
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
new QueryCursorPreparer(query));
} }
public <T> T findById(Object id, Class<T> entityClass) { public <T> T findById(Object id, Class<T> entityClass) {
@@ -512,7 +503,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
public <T> T findById(Object id, Class<T> entityClass, String collectionName) { public <T> T findById(Object id, Class<T> entityClass, String collectionName) {
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass); MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass);
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty(); MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
String idKey = idProperty == null ? ID : idProperty.getName(); String idKey = idProperty == null ? ID_FIELD : idProperty.getName();
return doFindOne(collectionName, new BasicDBObject(idKey, id), null, entityClass); return doFindOne(collectionName, new BasicDBObject(idKey, id), null, entityClass);
} }
@@ -657,6 +648,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
assertUpdateableIdIfNotSet(objectToSave); assertUpdateableIdIfNotSet(objectToSave);
initializeVersionProperty(objectToSave);
BasicDBObject dbDoc = new BasicDBObject(); BasicDBObject dbDoc = new BasicDBObject();
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave)); maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
@@ -669,6 +662,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc)); maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc));
} }
private void initializeVersionProperty(Object entity) {
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
if (mongoPersistentEntity == null || mongoPersistentEntity.hasVersionProperty()) {
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity, null);
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
}
}
public void insert(Collection<? extends Object> batchToSave, Class<?> entityClass) { public void insert(Collection<? extends Object> batchToSave, Class<?> entityClass) {
doInsertBatch(determineCollectionName(entityClass), batchToSave, this.mongoConverter); doInsertBatch(determineCollectionName(entityClass), batchToSave, this.mongoConverter);
} }
@@ -713,6 +716,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
List<DBObject> dbObjectList = new ArrayList<DBObject>(); List<DBObject> dbObjectList = new ArrayList<DBObject>();
for (T o : batchToSave) { for (T o : batchToSave) {
initializeVersionProperty(o);
BasicDBObject dbDoc = new BasicDBObject(); BasicDBObject dbDoc = new BasicDBObject();
maybeEmitEvent(new BeforeConvertEvent<T>(o)); maybeEmitEvent(new BeforeConvertEvent<T>(o));
@@ -785,7 +790,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
this.mongoConverter.write(objectToSave, dbObject); this.mongoConverter.write(objectToSave, dbObject);
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject)); maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject));
Update update = Update.fromDBObject(dbObject, ID); Update update = Update.fromDBObject(dbObject, ID_FIELD);
updateFirst(query, update, objectToSave.getClass()); updateFirst(query, update, objectToSave.getClass());
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject)); maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject));
@@ -820,21 +825,17 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
protected Object insertDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) { protected Object insertDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("insert DBObject containing fields: " + dbDoc.keySet() + " in collection: " + collectionName); LOGGER.debug("Inserting DBObject containing fields: " + dbDoc.keySet() + " in collection: " + collectionName);
} }
return execute(collectionName, new CollectionCallback<Object>() { return execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName, MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName,
entityClass, dbDoc, null); entityClass, dbDoc, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
WriteResult wr; WriteResult writeResult = writeConcernToUse == null ? collection.insert(dbDoc) : collection.insert(dbDoc,
if (writeConcernToUse == null) { writeConcernToUse);
wr = collection.insert(dbDoc); handleAnyWriteResultErrors(writeResult, dbDoc, MongoActionOperation.INSERT);
} else { return dbDoc.get(ID_FIELD);
wr = collection.insert(dbDoc, writeConcernToUse);
}
handleAnyWriteResultErrors(wr, dbDoc, "insert");
return dbDoc.get(ID);
} }
}); });
} }
@@ -845,27 +846,23 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("insert list of DBObjects containing " + dbDocList.size() + " items"); LOGGER.debug("Inserting list of DBObjects containing " + dbDocList.size() + " items");
} }
execute(collectionName, new CollectionCallback<Void>() { execute(collectionName, new CollectionCallback<Void>() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null, MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null,
null, null); null, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
WriteResult wr; WriteResult writeResult = writeConcernToUse == null ? collection.insert(dbDocList) : collection.insert(
if (writeConcernToUse == null) { dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
wr = collection.insert(dbDocList); handleAnyWriteResultErrors(writeResult, null, MongoActionOperation.INSERT_LIST);
} else {
wr = collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
}
handleAnyWriteResultErrors(wr, null, "insert_list");
return null; return null;
} }
}); });
List<ObjectId> ids = new ArrayList<ObjectId>(); List<ObjectId> ids = new ArrayList<ObjectId>();
for (DBObject dbo : dbDocList) { for (DBObject dbo : dbDocList) {
Object id = dbo.get(ID); Object id = dbo.get(ID_FIELD);
if (id instanceof ObjectId) { if (id instanceof ObjectId) {
ids.add((ObjectId) id); ids.add((ObjectId) id);
} else { } else {
@@ -878,21 +875,17 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
protected Object saveDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) { protected Object saveDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("save DBObject containing fields: " + dbDoc.keySet()); LOGGER.debug("Saving DBObject containing fields: " + dbDoc.keySet());
} }
return execute(collectionName, new CollectionCallback<Object>() { return execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass, MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass,
dbDoc, null); dbDoc, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
WriteResult wr; WriteResult writeResult = writeConcernToUse == null ? collection.save(dbDoc) : collection.save(dbDoc,
if (writeConcernToUse == null) { writeConcernToUse);
wr = collection.save(dbDoc); handleAnyWriteResultErrors(writeResult, dbDoc, MongoActionOperation.SAVE);
} else { return dbDoc.get(ID_FIELD);
wr = collection.save(dbDoc, writeConcernToUse);
}
handleAnyWriteResultErrors(wr, dbDoc, "save");
return dbDoc.get(ID);
} }
}); });
} }
@@ -935,29 +928,25 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
entity); entity);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("calling update using query: " + queryObj + " and update: " + updateObj + " in collection: " LOGGER.debug("Calling update using query: " + queryObj + " and update: " + updateObj + " in collection: "
+ collectionName); + collectionName);
} }
WriteResult wr;
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName, MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName,
entityClass, updateObj, queryObj); entityClass, updateObj, queryObj);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
if (writeConcernToUse == null) { WriteResult writeResult = writeConcernToUse == null ? collection.update(queryObj, updateObj, upsert, multi)
wr = collection.update(queryObj, updateObj, upsert, multi); : collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
} else {
wr = collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
}
if (entity != null && entity.hasVersionProperty() && !multi) { if (entity != null && entity.hasVersionProperty() && !multi) {
if (wr.getN() == 0) { if (writeResult.getN() == 0) {
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: " throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObj.toMap().toString()); + updateObj.toMap().toString());
} }
} }
handleAnyWriteResultErrors(wr, queryObj, "update with '" + updateObj + "'"); handleAnyWriteResultErrors(writeResult, queryObj, MongoActionOperation.UPDATE);
return wr; return writeResult;
} }
}); });
} }
@@ -1031,27 +1020,30 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
protected <T> void doRemove(final String collectionName, final Query query, final Class<T> entityClass) { protected <T> void doRemove(final String collectionName, final Query query, final Class<T> entityClass) {
if (query == null) { if (query == null) {
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null"); throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null");
} }
final DBObject queryObject = query.getQueryObject(); final DBObject queryObject = query.getQueryObject();
final MongoPersistentEntity<?> entity = getPersistentEntity(entityClass); final MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
execute(collectionName, new CollectionCallback<Void>() { execute(collectionName, new CollectionCallback<Void>() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
DBObject dboq = mapper.getMappedObject(queryObject, entity); DBObject dboq = mapper.getMappedObject(queryObject, entity);
WriteResult wr = null;
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.REMOVE, collectionName, MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.REMOVE, collectionName,
entityClass, null, queryObject); entityClass, null, queryObject);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction); WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("remove using query: " + dboq + " in collection: " + collection.getName()); LOGGER.debug("Remove using query: {} in collection: {}.", new Object[] { dboq, collection.getName() });
} }
if (writeConcernToUse == null) {
wr = collection.remove(dboq); WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
} else { writeConcernToUse);
wr = collection.remove(dboq, writeConcernToUse); handleAnyWriteResultErrors(wr, dboq, MongoActionOperation.REMOVE);
}
handleAnyWriteResultErrors(wr, dboq, "remove");
return null; return null;
} }
}); });
@@ -1108,7 +1100,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
handleCommandError(commandResult, commandObject); handleCommandError(commandResult, commandObject);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("MapReduce command result = [%s]", serializeToJsonSafely(commandObject))); LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(commandObject));
} }
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult); MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
@@ -1161,14 +1153,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBObject commandObject = new BasicDBObject("group", dbo); DBObject commandObject = new BasicDBObject("group", dbo);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Executing Group with DBObject [%s]", serializeToJsonSafely(commandObject))); LOGGER.debug("Executing Group with DBObject [{}]", serializeToJsonSafely(commandObject));
} }
CommandResult commandResult = executeCommand(commandObject, getDb().getOptions()); CommandResult commandResult = executeCommand(commandObject, getDb().getOptions());
handleCommandError(commandResult, commandObject); handleCommandError(commandResult, commandObject);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Group command result = [" + commandResult + "]"); LOGGER.debug("Group command result = [{}]", commandResult);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -1284,7 +1276,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBCollection coll = db.createCollection(collectionName, collectionOptions); DBCollection coll = db.createCollection(collectionName, collectionOptions);
// TODO: Emit a collection created event // TODO: Emit a collection created event
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Created collection [" + coll.getFullName() + "]"); LOGGER.debug("Created collection [{}]", coll.getFullName());
} }
return coll; return coll;
} }
@@ -1312,14 +1304,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
/** /**
* Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is
* <p/> * converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless configured
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless * otherwise, an instance of SimpleMongoConverter will be used. The query document is specified as a standard DBObject
* configured otherwise, an instance of SimpleMongoConverter will be used. * and so is the fields specification. Can be overridden by subclasses.
* <p/>
* 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 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 query the query document that specifies the criteria used to find a record
@@ -1350,9 +1338,8 @@ 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. * Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter. The
* <p/> * query document is specified as a standard DBObject and so is the fields specification.
* 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 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 query the query document that specifies the criteria used to find a record
@@ -1451,7 +1438,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
if (savedObject instanceof BasicDBObject) { if (savedObject instanceof BasicDBObject) {
DBObject dbObject = (DBObject) savedObject; DBObject dbObject = (DBObject) savedObject;
dbObject.put(ID, id); dbObject.put(ID_FIELD, id);
return; return;
} }
@@ -1531,19 +1518,32 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
CursorPreparer preparer, DbObjectCallback<T> objectCallback, String collectionName) { CursorPreparer preparer, DbObjectCallback<T> objectCallback, String collectionName) {
try { try {
DBCursor cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
if (preparer != null) { DBCursor cursor = null;
cursor = preparer.prepare(cursor);
try {
cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
if (preparer != null) {
cursor = preparer.prepare(cursor);
}
List<T> result = new ArrayList<T>();
while (cursor.hasNext()) {
DBObject object = cursor.next();
result.add(objectCallback.doWith(object));
}
return result;
} finally {
if (cursor != null) {
cursor.close();
}
} }
List<T> result = new ArrayList<T>();
for (DBObject object : cursor) {
result.add(objectCallback.doWith(object));
}
return result;
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e); throw potentiallyConvertRuntimeException(e);
} }
@@ -1553,15 +1553,27 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DocumentCallbackHandler callbackHandler, String collectionName) { DocumentCallbackHandler callbackHandler, String collectionName) {
try { try {
DBCursor cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
if (preparer != null) { DBCursor cursor = null;
cursor = preparer.prepare(cursor);
try {
cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
if (preparer != null) {
cursor = preparer.prepare(cursor);
}
while (cursor.hasNext()) {
DBObject dbobject = cursor.next();
callbackHandler.processDocument(dbobject);
}
} finally {
if (cursor != null) {
cursor.close();
}
} }
for (DBObject dbobject : cursor) {
callbackHandler.processDocument(dbobject);
}
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e); throw potentiallyConvertRuntimeException(e);
} }
@@ -1600,37 +1612,45 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
/** /**
* Checks and handles any errors. * Handles {@link WriteResult} errors based on the configured {@link WriteResultChecking}.
* <p/> *
* Current implementation logs errors. Future version may make this configurable to log warning, errors or throw * @param writeResult
* exception. * @param query
* @param operation
*/ */
protected void handleAnyWriteResultErrors(WriteResult wr, DBObject query, String operation) { protected void handleAnyWriteResultErrors(WriteResult writeResult, DBObject query, MongoActionOperation operation) {
if (WriteResultChecking.NONE == this.writeResultChecking) { if (writeResultChecking == WriteResultChecking.NONE) {
return; return;
} }
String error = wr.getError(); String error = writeResult.getError();
if (error != null) { if (error == null) {
String message; return;
if (operation.equals("insert") || operation.equals("save")) { }
// assuming the insert operations will begin with insert string
String message;
switch (operation) {
case INSERT:
case SAVE:
message = String.format("Insert/Save for %s failed: %s", query, error); message = String.format("Insert/Save for %s failed: %s", query, error);
} else if (operation.equals("insert_list")) { break;
case INSERT_LIST:
message = String.format("Insert list failed: %s", error); message = String.format("Insert list failed: %s", error);
} else { break;
default:
message = String.format("Execution of %s%s failed: %s", operation, message = String.format("Execution of %s%s failed: %s", operation,
query == null ? "" : "' using '" + query.toString() + "' query", error); query == null ? "" : " using query " + query.toString(), error);
} }
if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { if (writeResultChecking == WriteResultChecking.EXCEPTION) {
throw new DataIntegrityViolationException(message); throw new DataIntegrityViolationException(message);
} else { } else {
LOGGER.error(message); LOGGER.error(message);
return; return;
}
} }
} }
@@ -1718,7 +1738,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
private static class FindCallback implements CollectionCallback<DBCursor> { private static class FindCallback implements CollectionCallback<DBCursor> {
private final DBObject query; private final DBObject query;
private final DBObject fields; private final DBObject fields;
public FindCallback(DBObject query) { public FindCallback(DBObject query) {
@@ -1826,12 +1845,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
} }
private class DefaultWriteConcernResolver implements WriteConcernResolver { private enum DefaultWriteConcernResolver implements WriteConcernResolver {
INSTANCE;
public WriteConcern resolve(MongoAction action) { public WriteConcern resolve(MongoAction action) {
return action.getDefaultWriteConcern(); return action.getDefaultWriteConcern();
} }
} }
class QueryCursorPreparer implements CursorPreparer { class QueryCursorPreparer implements CursorPreparer {
@@ -1895,7 +1915,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DbObjectCallback} delegate for * Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DbObjectCallback} delegate for
* {@link GeoResult} content unmarshalling. * {@link GeoResult} content unmarshalling.
* *
* @param delegate * @param delegate must not be {@literal null}.
*/ */
public GeoNearResultDbObjectCallback(DbObjectCallback<T> delegate, Metric metric) { public GeoNearResultDbObjectCallback(DbObjectCallback<T> delegate, Metric metric) {
Assert.notNull(delegate); Assert.notNull(delegate);

View File

@@ -47,7 +47,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* Create an instance of {@link SimpleMongoDbFactory} given the {@link Mongo} instance and database name. * Create an instance of {@link SimpleMongoDbFactory} given the {@link Mongo} instance and database name.
* *
* @param mongo Mongo instance, must not be {@literal null}. * @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName database name, not be {@literal null}. * @param databaseName database name, not be {@literal null} or empty.
*/ */
public SimpleMongoDbFactory(Mongo mongo, String databaseName) { public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
this(mongo, databaseName, UserCredentials.NO_CREDENTIALS, false); this(mongo, databaseName, UserCredentials.NO_CREDENTIALS, false);
@@ -57,7 +57,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password * Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
* *
* @param mongo Mongo instance, must not be {@literal null}. * @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName Database name, must not be {@literal null}. * @param databaseName Database name, must not be {@literal null} or empty.
* @param credentials username and password. * @param credentials username and password.
*/ */
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) { public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,27 +13,25 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.data.mongodb.core; package org.springframework.data.mongodb.core;
import com.mongodb.WriteConcern; import com.mongodb.WriteConcern;
/** /**
* A strategy interface to determine the WriteConcern to use for a given MongoDbAction. * A strategy interface to determine the {@link WriteConcern} to use for a given {@link MongoAction}. Return the passed
* * in default {@link WriteConcern} (a property on {@link MongoAction}) if no determination can be made.
* Return the passed in default WriteConcern (a property on MongoAction) if no determination can be made.
* *
* @author Mark Pollack * @author Mark Pollack
* * @author Oliver Gierke
*/ */
public interface WriteConcernResolver { public interface WriteConcernResolver {
/** /**
* Resolve the WriteConcern given the MongoAction * Resolve the {@link WriteConcern} given the {@link MongoAction}.
* *
* @param action describes the context of the Mongo action. Contains a default WriteConcern to use if one should not * @param action describes the context of the Mongo action. Contains a default {@link WriteConcern} to use if one
* be resolved. * should not be resolved.
* @return a WriteConcern based on the passed in MongoAction value, maybe null * @return a {@link WriteConcern} based on the passed in {@link MongoAction} value, maybe {@literal null}.
*/ */
WriteConcern resolve(MongoAction action); WriteConcern resolve(MongoAction action);
} }

View File

@@ -1,5 +1,28 @@
/*
* 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; package org.springframework.data.mongodb.core;
/**
* Enum to represent how strict the check of {@link com.mongodb.WriteResult} shall be. It can either be skipped entirely
* (use {@link #NONE}), or errors can be logged ({@link #LOG}) or cause an exception to be thrown {@link #EXCEPTION}.
*
* @author Thomas Risberg
* @author Oliver Gierke
*/
public enum WriteResultChecking { public enum WriteResultChecking {
NONE, LOG, EXCEPTION NONE, LOG, EXCEPTION
} }

View File

@@ -1,11 +1,11 @@
/* /*
* Copyright (c) 2011 by the original author(s). * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.data.mongodb.core.convert; package org.springframework.data.mongodb.core.convert;
import java.math.BigInteger; import java.math.BigInteger;
@@ -33,8 +32,8 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.StringToObj
* Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic * Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
* converters. Allows registering {@link CustomConversions}. * converters. Allows registering {@link CustomConversions}.
* *
* @author Jon Brisbin <jbrisbin@vmware.com> * @author Jon Brisbin
* @author Oliver Gierke ogierke@vmware.com * @author Oliver Gierke
*/ */
public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean { public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean {
@@ -94,6 +93,14 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
conversions.registerConvertersIn(conversionService); conversions.registerConvertersIn(conversionService);
} }
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object)
*/
public Object convertToMongoType(Object obj) {
return convertToMongoType(obj, null);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService() * @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService()

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 by the original author(s). * Copyright 2011-2013 by the original author(s).
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -813,8 +813,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return rootList; return rootList;
} }
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object, org.springframework.data.util.TypeInformation)
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object convertToMongoType(Object obj) { public Object convertToMongoType(Object obj, TypeInformation<?> typeInformation) {
if (obj == null) { if (obj == null) {
return null; return null;
@@ -861,7 +865,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
DBObject newDbo = new BasicDBObject(); DBObject newDbo = new BasicDBObject();
this.write(obj, newDbo); this.write(obj, newDbo);
return removeTypeInfoRecursively(newDbo);
if (typeInformation == null) {
return removeTypeInfoRecursively(newDbo);
}
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo);
} }
public BasicDBList maybeConvertList(Iterable<?> source) { public BasicDBList maybeConvertList(Iterable<?> source) {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2012 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.convert;
import org.springframework.data.convert.EntityWriter; import org.springframework.data.convert.EntityWriter;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.util.TypeInformation;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.DBRef; import com.mongodb.DBRef;
@@ -35,11 +36,21 @@ public interface MongoWriter<T> extends EntityWriter<T, DBObject> {
* Converts the given object into one Mongo will be able to store natively. If the given object can already be stored * Converts the given object into one Mongo will be able to store natively. If the given object can already be stored
* as is, no conversion will happen. * as is, no conversion will happen.
* *
* @param obj * @param obj can be {@literal null}.
* @return * @return
*/ */
Object convertToMongoType(Object obj); Object convertToMongoType(Object obj);
/**
* Converts the given object into one Mongo will be able to store natively but retains the type information in case
* the given {@link TypeInformation} differs from the given object type.
*
* @param obj can be {@literal null}.
* @param typeInformation can be {@literal null}.
* @return
*/
Object convertToMongoType(Object obj, TypeInformation<?> typeInformation);
/** /**
* Creates a {@link DBRef} to refer to the given object. * Creates a {@link DBRef} to refer to the given object.
* *

View File

@@ -263,7 +263,7 @@ public class QueryMapper {
return result; return result;
} }
return source instanceof DBRef ? source : converter.toDBRef(source, property); return source == null || source instanceof DBRef ? source : converter.toDBRef(source, property);
} }
/** /**

View File

@@ -117,7 +117,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
protected List<?> readCollection(Query query) { protected List<?> readCollection(Query query) {
MongoEntityInformation<?, ?> metadata = method.getEntityInformation(); MongoEntityMetadata<?> metadata = method.getEntityInformation();
String collectionName = metadata.getCollectionName(); String collectionName = metadata.getCollectionName();
return operations.find(query, metadata.getJavaType(), collectionName); return operations.find(query, metadata.getJavaType(), collectionName);
@@ -175,7 +175,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
Object execute(Query query) { Object execute(Query query) {
MongoEntityInformation<?, ?> metadata = method.getEntityInformation(); MongoEntityMetadata<?> metadata = method.getEntityInformation();
long count = operations.count(query, metadata.getCollectionName()); long count = operations.count(query, metadata.getCollectionName());
List<?> result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName()); List<?> result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName());
@@ -198,8 +198,8 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
@Override @Override
Object execute(Query query) { Object execute(Query query) {
MongoEntityInformation<?, ?> entityInformation = method.getEntityInformation(); MongoEntityMetadata<?> metadata = method.getEntityInformation();
return operations.findOne(query, entityInformation.getJavaType()); return operations.findOne(query, metadata.getJavaType());
} }
} }
@@ -236,8 +236,8 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
*/ */
Object execute(Query query, Query countQuery) { Object execute(Query query, Query countQuery) {
MongoEntityInformation<?, ?> information = method.getEntityInformation(); MongoEntityMetadata<?> metadata = method.getEntityInformation();
long count = operations.count(countQuery, information.getCollectionName()); long count = operations.count(countQuery, metadata.getCollectionName());
return new GeoPage<Object>(doExecuteQuery(query), accessor.getPageable(), count); return new GeoPage<Object>(doExecuteQuery(query), accessor.getPageable(), count);
} }
@@ -257,9 +257,8 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
nearQuery.maxDistance(maxDistance); nearQuery.maxDistance(maxDistance);
} }
MongoEntityInformation<?, ?> entityInformation = method.getEntityInformation(); MongoEntityMetadata<?> metadata = method.getEntityInformation();
return (GeoResults<Object>) operations.geoNear(nearQuery, entityInformation.getJavaType(), return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
entityInformation.getCollectionName());
} }
private boolean isListOfGeoResult() { private boolean isListOfGeoResult() {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Point; import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -85,12 +86,12 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
return delegate.getSort(); return delegate.getSort();
} }
/* (non-Javadoc) /*
* @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) * (non-Javadoc)
*/ * @see org.springframework.data.repository.query.ParameterAccessor#getBindableValue(int)
*/
public Object getBindableValue(int index) { public Object getBindableValue(int index) {
return getConvertedValue(delegate.getBindableValue(index), null);
return getConvertedValue(delegate.getBindableValue(index));
} }
/* /*
@@ -101,7 +102,8 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
return delegate.getMaxDistance(); return delegate.getMaxDistance();
} }
/* (non-Javadoc) /*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.MongoParameterAccessor#getGeoNearLocation() * @see org.springframework.data.mongodb.repository.MongoParameterAccessor#getGeoNearLocation()
*/ */
public Point getGeoNearLocation() { public Point getGeoNearLocation() {
@@ -111,11 +113,12 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
/** /**
* Converts the given value with the underlying {@link MongoWriter}. * Converts the given value with the underlying {@link MongoWriter}.
* *
* @param value * @param value can be {@literal null}.
* @param typeInformation can be {@literal null}.
* @return * @return
*/ */
private Object getConvertedValue(Object value) { private Object getConvertedValue(Object value, TypeInformation<?> typeInformation) {
return writer.convertToMongoType(value); return writer.convertToMongoType(value, typeInformation == null ? null : typeInformation.getActualType());
} }
/* /*
@@ -186,7 +189,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
} }
} }
return getConvertedValue(next); return getConvertedValue(next, property.getTypeInformation());
} }
/* /*

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2011 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.repository.query;
import java.io.Serializable;
/**
* Interface for components being able to provide {@link EntityInformationCreator} for a given {@link Class}.
*
* @author Oliver Gierke
*/
public interface EntityInformationCreator {
/**
* Returns a {@link MongoEntityInformation} for the given domain class.
*
* @param domainClass the domain class to create the {@link MongoEntityInformation} for, must not be {@literal null}.
* @return
*/
<T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass);
/**
* Returns a {@link MongoEntityInformation} for the given domain class and class to retrieve the collection to query
* against from.
*
* @param domainClass the domain class to create the {@link MongoEntityInformation} for, must not be {@literal null}.
* @param collectionClass the class to derive the collection from queries to retrieve the domain classes from shall be
* ran against, must not be {@literal null}.
* @return
*/
<T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass,
Class<?> collectionClass);
}

View File

@@ -0,0 +1,33 @@
/*
* 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.repository.query;
import org.springframework.data.repository.core.EntityMetadata;
/**
* Extension of {@link EntityMetadata} to additionally expose the collection name an entity shall be persisted to.
*
* @author Oliver Gierke
*/
public interface MongoEntityMetadata<T> extends EntityMetadata<T> {
/**
* Returns the name of the collection the entity shall be persisted to.
*
* @return
*/
String getCollectionName();
}

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,9 +20,12 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.geo.GeoPage; import org.springframework.data.mongodb.core.geo.GeoPage;
import org.springframework.data.mongodb.core.geo.GeoResult; import org.springframework.data.mongodb.core.geo.GeoResult;
import org.springframework.data.mongodb.core.geo.GeoResults; import org.springframework.data.mongodb.core.geo.GeoResults;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.Parameters;
@@ -33,8 +36,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* TODO - Extract methods for {@link #getAnnotatedQuery()} into superclass as it is currently copied from Spring Data * Mongo specific implementation of {@link QueryMethod}.
* JPA
* *
* @author Oliver Gierke * @author Oliver Gierke
*/ */
@@ -45,19 +47,24 @@ public class MongoQueryMethod extends QueryMethod {
.asList(GeoResult.class, GeoResults.class, GeoPage.class); .asList(GeoResult.class, GeoResults.class, GeoPage.class);
private final Method method; private final Method method;
private final MongoEntityInformation<?, ?> entityInformation; private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private MongoEntityMetadata<?> metadata;
/** /**
* Creates a new {@link MongoQueryMethod} from the given {@link Method}. * Creates a new {@link MongoQueryMethod} from the given {@link Method}.
* *
* @param method * @param method
*/ */
public MongoQueryMethod(Method method, RepositoryMetadata metadata, EntityInformationCreator entityInformationCreator) { public MongoQueryMethod(Method method, RepositoryMetadata metadata,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
super(method, metadata); super(method, metadata);
Assert.notNull(entityInformationCreator, "DefaultEntityInformationCreator must not be null!");
Assert.notNull(mappingContext, "MappingContext must not be null!");
this.method = method; this.method = method;
this.entityInformation = entityInformationCreator.getEntityInformation(metadata.getReturnedDomainClass(method), this.mappingContext = mappingContext;
getDomainClass());
} }
/* /*
@@ -101,14 +108,30 @@ public class MongoQueryMethod extends QueryMethod {
return StringUtils.hasText(value) ? value : null; return StringUtils.hasText(value) ? value : null;
} }
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.repository.query.QueryMethod#getEntityInformation() * @see org.springframework.data.repository.query.QueryMethod#getEntityInformation()
*/ */
@Override @Override
public MongoEntityInformation<?, ?> getEntityInformation() { @SuppressWarnings("unchecked")
public MongoEntityMetadata<?> getEntityInformation() {
return entityInformation; if (metadata == null) {
Class<?> returnedObjectType = getReturnedObjectType();
Class<?> domainClass = getDomainClass();
MongoPersistentEntity<?> returnedEntity = mappingContext.getPersistentEntity(getReturnedObjectType());
MongoPersistentEntity<?> managedEntity = mappingContext.getPersistentEntity(domainClass);
returnedEntity = returnedEntity == null ? managedEntity : returnedEntity;
MongoPersistentEntity<?> collectionEntity = domainClass.isAssignableFrom(returnedObjectType) ? returnedEntity
: managedEntity;
this.metadata = new SimpleMongoEntityMetadata<Object>((Class<Object>) returnedEntity.getType(),
collectionEntity.getCollection());
}
return this.metadata;
} }
/* /*
@@ -121,12 +144,11 @@ public class MongoQueryMethod extends QueryMethod {
} }
/** /**
* Returns whether te query is a geoNear query. * Returns whether te query is a geo near query.
* *
* @return * @return
*/ */
public boolean isGeoNearQuery() { public boolean isGeoNearQuery() {
return isGeoNearQuery(this.method); return isGeoNearQuery(this.method);
} }

View File

@@ -0,0 +1,60 @@
/*
* 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.repository.query;
import org.springframework.util.Assert;
/**
* Bean based implementation of {@link MongoEntityMetadata}.
*
* @author Oliver Gierke
*/
class SimpleMongoEntityMetadata<T> implements MongoEntityMetadata<T> {
private final Class<T> type;
private final String collectionName;
/**
* Creates a new {@link SimpleMongoEntityMetadata} using the given type and collection name.
*
* @param type must not be {@literal null}.
* @param collectionName must not be {@literal null} or empty.
*/
public SimpleMongoEntityMetadata(Class<T> type, String collectionName) {
Assert.notNull(type, "Type must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
this.type = type;
this.collectionName = collectionName;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.EntityMetadata#getJavaType()
*/
public Class<T> getJavaType() {
return type;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.MongoEntityMetadata#getCollectionName()
*/
public String getCollectionName() {
return collectionName;
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2011 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.repository.support;
import java.io.Serializable;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.repository.query.EntityInformationCreator;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.util.Assert;
/**
* Simple {@link EntityInformationCreator} to to create {@link MongoEntityInformation} instances based on a
* {@link MappingContext}.
*
* @author Oliver Gierke
*/
public class DefaultEntityInformationCreator implements EntityInformationCreator {
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
public DefaultEntityInformationCreator(
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
Assert.notNull(mappingContext);
this.mappingContext = mappingContext;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.support.EntityInformationCreator#getEntityInformation(java.lang.Class)
*/
public <T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return getEntityInformation(domainClass, null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.support.EntityInformationCreator#getEntityInformation(java.lang.Class, java.lang.Class)
*/
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass,
Class<?> collectionClass) {
MongoPersistentEntity<T> persistentEntity = (MongoPersistentEntity<T>) mappingContext
.getPersistentEntity(domainClass);
String customCollectionName = collectionClass == null ? null : mappingContext.getPersistentEntity(collectionClass)
.getCollection();
return new MappingMongoEntityInformation<T, ID>(persistentEntity, customCollectionName);
}
}

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.index.Index; import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.query.Order; import org.springframework.data.mongodb.core.query.Order;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation; import org.springframework.data.mongodb.repository.query.MongoEntityMetadata;
import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery; import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery;
import org.springframework.data.mongodb.repository.query.QueryUtils; import org.springframework.data.mongodb.repository.query.QueryUtils;
import org.springframework.data.repository.core.support.QueryCreationListener; import org.springframework.data.repository.core.support.QueryCreationListener;
@@ -85,7 +85,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
} }
} }
MongoEntityInformation<?, ?> metadata = query.getQueryMethod().getEntityInformation(); MongoEntityMetadata<?> metadata = query.getQueryMethod().getEntityInformation();
operations.indexOps(metadata.getCollectionName()).ensureIndex(index); operations.indexOps(metadata.getCollectionName()).ensureIndex(index);
LOG.debug(String.format("Created %s!", index)); LOG.debug(String.format("Created %s!", index));
} }
@@ -99,4 +99,4 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
org.springframework.data.domain.Sort.Order order = sort.getOrderFor(property); org.springframework.data.domain.Sort.Order order = sort.getOrderFor(property);
return order == null ? Order.DESCENDING : order.isAscending() ? Order.ASCENDING : Order.DESCENDING; return order == null ? Order.DESCENDING : order.isAscending() ? Order.ASCENDING : Order.DESCENDING;
} }
} }

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,10 +21,11 @@ import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
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.repository.MongoRepository; import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.query.EntityInformationCreator;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation; import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.query.MongoQueryMethod; import org.springframework.data.mongodb.repository.query.MongoQueryMethod;
import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery; import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery;
@@ -46,20 +47,18 @@ import org.springframework.util.Assert;
public class MongoRepositoryFactory extends RepositoryFactorySupport { public class MongoRepositoryFactory extends RepositoryFactorySupport {
private final MongoOperations mongoOperations; private final MongoOperations mongoOperations;
private final EntityInformationCreator entityInformationCreator; private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
/** /**
* Creates a new {@link MongoRepositoryFactory} with the given {@link MongoTemplate} and {@link MappingContext}. * Creates a new {@link MongoRepositoryFactory} with the given {@link MongoOperations}.
* *
* @param template must not be {@literal null} * @param mongoOperations must not be {@literal null}
* @param mappingContext
*/ */
public MongoRepositoryFactory(MongoOperations mongoOperations) { public MongoRepositoryFactory(MongoOperations mongoOperations) {
Assert.notNull(mongoOperations); Assert.notNull(mongoOperations);
this.mongoOperations = mongoOperations; this.mongoOperations = mongoOperations;
this.entityInformationCreator = new DefaultEntityInformationCreator(mongoOperations.getConverter() this.mappingContext = mongoOperations.getConverter().getMappingContext();
.getMappingContext());
} }
/* /*
@@ -117,7 +116,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
*/ */
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) { public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, entityInformationCreator); MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, mappingContext);
String namedQueryName = queryMethod.getNamedQueryName(); String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) { if (namedQueries.hasQuery(namedQueryName)) {
@@ -136,7 +135,16 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class) * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) { public <T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return entityInformationCreator.getEntityInformation(domainClass);
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(domainClass);
if (entity == null) {
throw new MappingException(String.format("Could not lookup mapping metadata for domain class %s!",
domainClass.getName()));
}
return new MappingMongoEntityInformation<T, ID>((MongoPersistentEntity<T>) entity);
} }
} }

View File

@@ -0,0 +1,124 @@
/*
* 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.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* Integration tests for {@link MongoDbUtils}.
*
* @author Oliver Gierke
*/
public class MongoDbUtilsIntegrationTests {
static final String DATABASE_NAME = "dbAuthTests";
static final UserCredentials CREDENTIALS = new UserCredentials("admin", "admin");
static Mongo mongo;
static MongoTemplate template;
static ThreadPoolExecutorFactoryBean factory;
static ExecutorService service;
Exception exception;
@BeforeClass
public static void setUp() throws Exception {
mongo = new Mongo();
template = new MongoTemplate(mongo, DATABASE_NAME);
// Create sample user
template.execute(new DbCallback<Void>() {
public Void doInDB(DB db) throws MongoException, DataAccessException {
db.addUser("admin", "admin".toCharArray());
return null;
}
});
factory = new ThreadPoolExecutorFactoryBean();
factory.setCorePoolSize(2);
factory.setMaxPoolSize(10);
factory.setWaitForTasksToCompleteOnShutdown(true);
factory.afterPropertiesSet();
service = factory.getObject();
}
@AfterClass
public static void tearDown() {
factory.destroy();
// Remove test database
template.execute(new DbCallback<Void>() {
public Void doInDB(DB db) throws MongoException, DataAccessException {
db.dropDatabase();
return null;
}
});
}
/**
* @see DATAMONGO-585
*/
@Test
public void authenticatesCorrectlyInMultithreadedEnvironment() throws Exception {
Callable<Void> callable = new Callable<Void>() {
public Void call() throws Exception {
try {
DB db = MongoDbUtils.getDB(mongo, DATABASE_NAME, CREDENTIALS);
assertThat(db, is(notNullValue()));
} catch (Exception o_O) {
MongoDbUtilsIntegrationTests.this.exception = o_O;
}
return null;
}
};
List<Callable<Void>> callables = new ArrayList<Callable<Void>>();
for (int i = 0; i < 10; i++) {
callables.add(callable);
}
service.invokeAll(callables);
if (exception != null) {
fail("Exception occurred!" + exception);
}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.net.UnknownHostException;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.NestedRuntimeException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import com.mongodb.MongoException;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
import com.mongodb.MongoInternalException;
import com.mongodb.ServerAddress;
/**
* Unit tests for {@link MongoExceptionTranslator}.
*
* @author Michal Vich
* @author Oliver Gierke
*/
public class MongoExceptionTranslatorUnitTests {
MongoExceptionTranslator translator;
@Before
public void setUp() {
translator = new MongoExceptionTranslator();
}
@Test
public void translateDuplicateKey() {
DuplicateKey exception = new DuplicateKey(1, "Duplicated key");
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
expectExceptionWithCauseMessage(translatedException, DuplicateKeyException.class, "Duplicated key");
}
@Test
public void translateNetwork() {
Network exception = new Network("IOException", new IOException("IOException"));
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
expectExceptionWithCauseMessage(translatedException, DataAccessResourceFailureException.class, "IOException");
}
@Test
public void translateCursorNotFound() throws UnknownHostException {
MongoException.CursorNotFound exception = new MongoException.CursorNotFound(1, new ServerAddress());
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
expectExceptionWithCauseMessage(translatedException, DataAccessResourceFailureException.class);
}
@Test
public void translateToDuplicateKeyException() {
checkTranslatedMongoException(DuplicateKeyException.class, 11000);
checkTranslatedMongoException(DuplicateKeyException.class, 11001);
}
@Test
public void translateToDataAccessResourceFailureException() {
checkTranslatedMongoException(DataAccessResourceFailureException.class, 12000);
checkTranslatedMongoException(DataAccessResourceFailureException.class, 13440);
}
@Test
public void translateToInvalidDataAccessApiUsageException() {
checkTranslatedMongoException(InvalidDataAccessApiUsageException.class, 10003);
checkTranslatedMongoException(InvalidDataAccessApiUsageException.class, 12001);
checkTranslatedMongoException(InvalidDataAccessApiUsageException.class, 12010);
checkTranslatedMongoException(InvalidDataAccessApiUsageException.class, 12011);
checkTranslatedMongoException(InvalidDataAccessApiUsageException.class, 12012);
}
@Test
public void translateToUncategorizedMongoDbException() {
MongoException exception = new MongoException(0, "");
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
expectExceptionWithCauseMessage(translatedException, UncategorizedMongoDbException.class);
}
@Test
public void translateMongoInternalException() {
MongoInternalException exception = new MongoInternalException("Internal exception");
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
expectExceptionWithCauseMessage(translatedException, InvalidDataAccessResourceUsageException.class);
}
@Test
public void translateUnsupportedException() {
RuntimeException exception = new RuntimeException();
assertThat(translator.translateExceptionIfPossible(exception), is(nullValue()));
}
private void checkTranslatedMongoException(Class<? extends Exception> clazz, int code) {
try {
translator.translateExceptionIfPossible(new MongoException(code, ""));
fail("Expected exception of type " + clazz.getName() + "!");
} catch (NestedRuntimeException e) {
Throwable cause = e.getRootCause();
assertThat(cause, is(instanceOf(MongoException.class)));
assertThat(((MongoException) cause).getCode(), is(code));
}
}
private static void expectExceptionWithCauseMessage(NestedRuntimeException e,
Class<? extends NestedRuntimeException> type) {
expectExceptionWithCauseMessage(e, type, null);
}
private static void expectExceptionWithCauseMessage(NestedRuntimeException e,
Class<? extends NestedRuntimeException> type, String message) {
assertThat(e, is(instanceOf(type)));
if (message != null) {
assertThat(e.getRootCause(), is(notNullValue()));
assertThat(e.getRootCause().getMessage(), containsString(message));
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.util.TypeInformation;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import com.mongodb.DBObject; import com.mongodb.DBObject;
@@ -78,7 +79,7 @@ public abstract class MongoOperationsUnitTests {
return null; return null;
} }
public Object convertToMongoType(Object obj) { public Object convertToMongoType(Object obj, TypeInformation<?> typeInformation) {
return null; return null;
} }

View File

@@ -212,19 +212,14 @@ public class MongoTemplateTests {
template.insert(person); template.insert(person);
try { thrown.expect(DataIntegrityViolationException.class);
thrown.expectMessage("Execution");
thrown.expectMessage("$push");
thrown.expectMessage("firstName");
Query query = new Query(Criteria.where("firstName").is("Amol")); Query query = new Query(Criteria.where("firstName").is("Amol"));
Update upd = new Update().push("age", 29); Update upd = new Update().push("age", 29);
template.updateFirst(query, upd, Person.class); template.updateFirst(query, upd, Person.class);
fail("Expected DataIntegrityViolationException!");
} catch (DataIntegrityViolationException e) {
assertThat(e.getMessage(),
is("Execution of update with '{ \"$push\" : { \"age\" : 29}}'' using '{ \"firstName\" : \"Amol\"}' "
+ "query failed: Cannot apply $push/$pushAll modifier to non-array"));
}
} }
/** /**
@@ -1028,7 +1023,7 @@ public class MongoTemplateTests {
assertThat(lastMongoAction.getCollectionName(), is("personWithIdPropertyOfTypeObjectId")); assertThat(lastMongoAction.getCollectionName(), is("personWithIdPropertyOfTypeObjectId"));
assertThat(lastMongoAction.getDefaultWriteConcern(), equalTo(WriteConcern.NONE)); assertThat(lastMongoAction.getDefaultWriteConcern(), equalTo(WriteConcern.NONE));
assertThat(lastMongoAction.getDocument(), notNullValue()); assertThat(lastMongoAction.getDocument(), notNullValue());
assertThat(lastMongoAction.getEntityClass().toString(), is(PersonWithIdPropertyOfTypeObjectId.class.toString())); assertThat(lastMongoAction.getEntityType().toString(), is(PersonWithIdPropertyOfTypeObjectId.class.toString()));
assertThat(lastMongoAction.getMongoActionOperation(), is(MongoActionOperation.UPDATE)); assertThat(lastMongoAction.getMongoActionOperation(), is(MongoActionOperation.UPDATE));
assertThat(lastMongoAction.getQuery(), equalTo(q.getQueryObject())); assertThat(lastMongoAction.getQuery(), equalTo(q.getQueryObject()));
@@ -1422,6 +1417,44 @@ public class MongoTemplateTests {
template.save("Foobar!", "collection"); template.save("Foobar!", "collection");
} }
/**
* @see DATAMONGO-588
*/
@Test
public void initializesVersionOnInsert() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.insert(person);
assertThat(person.version, is(0));
}
/**
* @see DATAMONGO-588
*/
@Test
public void initializesVersionOnBatchInsert() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.insertAll(Arrays.asList(person));
assertThat(person.version, is(0));
}
/**
* @see DATAMONGO-568
*/
@Test
public void queryCantBeNull() {
List<PersonWithIdPropertyOfTypeObjectId> result = template.findAll(PersonWithIdPropertyOfTypeObjectId.class);
assertThat(template.find(null, PersonWithIdPropertyOfTypeObjectId.class), is(result));
}
static class MyId { static class MyId {
String first; String first;

View File

@@ -335,6 +335,18 @@ public class QueryMapperUnitTests {
assertThat(reference.containsField("$in"), is(true)); assertThat(reference.containsField("$in"), is(true));
} }
/**
* @see DATAMONGO-570
*/
@Test
public void correctlyConvertsNullReference() {
Query query = query(where("reference").is(null));
DBObject object = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
assertThat(object.get("reference"), is(nullValue()));
}
class IdWrapper { class IdWrapper {
Object id; Object id;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -523,4 +523,23 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
assertThat(result, hasSize(1)); assertThat(result, hasSize(1));
assertThat(result, hasItem(oliver)); assertThat(result, hasItem(oliver));
} }
/**
* @see DATAMONGO-600
*/
@Test
public void readsDocumentsWithNestedPolymorphismCorrectly() {
UsernameAndPassword usernameAndPassword = new UsernameAndPassword();
usernameAndPassword.username = "dave";
usernameAndPassword.password = "btcs";
dave.credentials = usernameAndPassword;
repository.save(dave);
List<Person> result = repository.findByCredentials(usernameAndPassword);
assertThat(result, hasSize(1));
assertThat(result, hasItem(dave));
}
} }

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository;
/**
*
* @author Oliver Gierke
*/
public interface Credentials {
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2011 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -54,6 +54,8 @@ public class Person extends Contact {
@DBRef @DBRef
User creator; User creator;
Credentials credentials;
public Person() { public Person() {
this(null, null); this(null, null);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2012 the original author or authors. * Copyright 2010-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -192,4 +192,10 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
*/ */
List<Person> findByLastnameNot(String lastname); List<Person> findByLastnameNot(String lastname);
/**
* @see DATAMONGO-600
* @param credentials
* @return
*/
List<Person> findByCredentials(Credentials credentials);
} }

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository;
/**
* @author Oliver Gierke
*/
public class UsernameAndPassword implements Credentials {
String username;
String password;
}

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import org.springframework.data.mongodb.core.geo.Metrics;
import org.springframework.data.mongodb.core.geo.Point; import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.Person; import org.springframework.data.mongodb.repository.Person;
import org.springframework.data.mongodb.repository.support.DefaultEntityInformationCreator;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
@@ -42,13 +41,12 @@ public class MongoParametersParameterAccessorUnitTests {
private static final Distance DISTANCE = new Distance(2.5, Metrics.KILOMETERS); private static final Distance DISTANCE = new Distance(2.5, Metrics.KILOMETERS);
private static final RepositoryMetadata metadata = new DefaultRepositoryMetadata(PersonRepository.class); private static final RepositoryMetadata metadata = new DefaultRepositoryMetadata(PersonRepository.class);
private static final MongoMappingContext context = new MongoMappingContext(); private static final MongoMappingContext context = new MongoMappingContext();
private static final EntityInformationCreator creator = new DefaultEntityInformationCreator(context);
@Test @Test
public void returnsNullForDistanceIfNoneAvailable() throws NoSuchMethodException, SecurityException { public void returnsNullForDistanceIfNoneAvailable() throws NoSuchMethodException, SecurityException {
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class); Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, creator); MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, context);
MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod, MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod,
new Object[] { new Point(10, 20) }); new Object[] { new Point(10, 20) });
@@ -59,7 +57,7 @@ public class MongoParametersParameterAccessorUnitTests {
public void returnsDistanceIfAvailable() throws NoSuchMethodException, SecurityException { public void returnsDistanceIfAvailable() throws NoSuchMethodException, SecurityException {
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class); Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, creator); MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, context);
MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod, new Object[] { MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod, new Object[] {
new Point(10, 20), DISTANCE }); new Point(10, 20), DISTANCE });

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 the original author or authors. * Copyright 2011-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -46,10 +46,10 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.support.DefaultEntityInformationCreator;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.TypeInformation;
/** /**
* Unit test for {@link MongoQueryCreator}. * Unit test for {@link MongoQueryCreator}.
@@ -75,7 +75,7 @@ public class MongoQueryCreatorUnitTests {
public Object answer(InvocationOnMock invocation) throws Throwable { public Object answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArguments()[0]; return invocation.getArguments()[0];
} }
}).when(converter).convertToMongoType(any()); }).when(converter).convertToMongoType(any(), Mockito.any(TypeInformation.class));
} }
@Test @Test
@@ -301,7 +301,7 @@ public class MongoQueryCreatorUnitTests {
Method method = PersonRepository.class.getMethod("findByLocationNearAndFirstname", Point.class, Distance.class, Method method = PersonRepository.class.getMethod("findByLocationNearAndFirstname", Point.class, Distance.class,
String.class); String.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class), MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class),
new DefaultEntityInformationCreator(new MongoMappingContext())); new MongoMappingContext());
MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod, new Object[] { point, distance, MongoParameterAccessor accessor = new MongoParametersParameterAccessor(queryMethod, new Object[] { point, distance,
"Dave" }); "Dave" });

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@@ -35,7 +35,6 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.Address; import org.springframework.data.mongodb.repository.Address;
import org.springframework.data.mongodb.repository.Contact; import org.springframework.data.mongodb.repository.Contact;
import org.springframework.data.mongodb.repository.Person; import org.springframework.data.mongodb.repository.Person;
import org.springframework.data.mongodb.repository.support.DefaultEntityInformationCreator;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
@@ -46,12 +45,11 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat
*/ */
public class MongoQueryMethodUnitTests { public class MongoQueryMethodUnitTests {
EntityInformationCreator creator; MongoMappingContext context;
@Before @Before
public void setUp() { public void setUp() {
MongoMappingContext context = new MongoMappingContext(); context = new MongoMappingContext();
creator = new DefaultEntityInformationCreator(context);
} }
@Test @Test
@@ -60,11 +58,11 @@ public class MongoQueryMethodUnitTests {
Method method = SampleRepository.class.getMethod("method"); Method method = SampleRepository.class.getMethod("method");
MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class), MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
creator); context);
MongoEntityInformation<?, ?> entityInformation = queryMethod.getEntityInformation(); MongoEntityMetadata<?> metadata = queryMethod.getEntityInformation();
assertThat(entityInformation.getJavaType(), is(typeCompatibleWith(Address.class))); assertThat(metadata.getJavaType(), is(typeCompatibleWith(Address.class)));
assertThat(entityInformation.getCollectionName(), is("contact")); assertThat(metadata.getCollectionName(), is("contact"));
} }
@Test @Test
@@ -73,8 +71,8 @@ public class MongoQueryMethodUnitTests {
Method method = SampleRepository2.class.getMethod("method"); Method method = SampleRepository2.class.getMethod("method");
MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class), MongoQueryMethod queryMethod = new MongoQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
creator); context);
MongoEntityInformation<?, ?> entityInformation = queryMethod.getEntityInformation(); MongoEntityMetadata<?> entityInformation = queryMethod.getEntityInformation();
assertThat(entityInformation.getJavaType(), is(typeCompatibleWith(Person.class))); assertThat(entityInformation.getJavaType(), is(typeCompatibleWith(Person.class)));
assertThat(entityInformation.getCollectionName(), is("person")); assertThat(entityInformation.getCollectionName(), is("person"));
@@ -103,7 +101,7 @@ public class MongoQueryMethodUnitTests {
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void rejectsNullEntityCreator() throws Exception { public void rejectsNullMappingContext() throws Exception {
Method method = PersonRepository.class.getMethod("findByFirstname", String.class, Point.class); Method method = PersonRepository.class.getMethod("findByFirstname", String.class, Point.class);
new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class), null); new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class), null);
} }
@@ -115,9 +113,16 @@ public class MongoQueryMethodUnitTests {
assertThat(method.isCollectionQuery(), is(false)); assertThat(method.isCollectionQuery(), is(false));
} }
@Test
public void createsMongoQueryMethodObjectForMethodReturningAnInterface() throws Exception {
Method method = SampleRepository2.class.getMethod("methodReturningAnInterface");
new MongoQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository2.class), context);
}
private MongoQueryMethod queryMethod(String name, Class<?>... parameters) throws Exception { private MongoQueryMethod queryMethod(String name, Class<?>... parameters) throws Exception {
Method method = PersonRepository.class.getMethod(name, parameters); Method method = PersonRepository.class.getMethod(name, parameters);
return new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class), creator); return new MongoQueryMethod(method, new DefaultRepositoryMetadata(PersonRepository.class), context);
} }
interface PersonRepository extends Repository<User, Long> { interface PersonRepository extends Repository<User, Long> {
@@ -142,5 +147,11 @@ public class MongoQueryMethodUnitTests {
interface SampleRepository2 extends Repository<Contact, Long> { interface SampleRepository2 extends Repository<Contact, Long> {
List<Person> method(); List<Person> method();
Customer methodReturningAnInterface();
}
interface Customer {
} }
} }

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -54,8 +54,6 @@ public class StringBasedMongoQueryUnitTests {
@Mock @Mock
RepositoryMetadata metadata; RepositoryMetadata metadata;
@Mock @Mock
EntityInformationCreator creator;
@Mock
MongoDbFactory factory; MongoDbFactory factory;
MongoConverter converter; MongoConverter converter;
@@ -70,7 +68,7 @@ public class StringBasedMongoQueryUnitTests {
public void bindsSimplePropertyCorrectly() throws Exception { public void bindsSimplePropertyCorrectly() throws Exception {
Method method = SampleRepository.class.getMethod("findByLastname", String.class); Method method = SampleRepository.class.getMethod("findByLastname", String.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, creator); MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, converter.getMappingContext());
StringBasedMongoQuery mongoQuery = new StringBasedMongoQuery(queryMethod, operations); StringBasedMongoQuery mongoQuery = new StringBasedMongoQuery(queryMethod, operations);
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews"); ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews");
@@ -132,7 +130,7 @@ public class StringBasedMongoQueryUnitTests {
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception { private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
Method method = SampleRepository.class.getMethod(name, parameters); Method method = SampleRepository.class.getMethod(name, parameters);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, creator); MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, converter.getMappingContext());
return new StringBasedMongoQuery(queryMethod, operations); return new StringBasedMongoQuery(queryMethod, operations);
} }

View File

@@ -1,11 +0,0 @@
log4j.rootCategory=ERROR, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
#log4j.category.org.springframework.data=DEBUG
log4j.category.org.hibernate.SQL=DEBUG
# for debugging datasource initialization
# log4j.category.test.jdbc=DEBUG

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<!--
<logger name="org.springframework" level="debug" />
-->
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -0,0 +1 @@
handlers = org.slf4j.bridge.SLF4JBridgeHandler

View File

@@ -1,5 +1,29 @@
Spring Data MongoDB Changelog Spring Data MongoDB Changelog
============================================= =============================
Changes in version 1.1.2.GA (2013-02-08)
----------------------------------------
** Bug
* [DATAMONGO-562] - Cannot create entity with OptimisticLocking (@Version) and initial id
* [DATAMONGO-568] - MongoTemplate.find(...) method causes Nullpointer if query parameter is null
* [DATAMONGO-570] - Query methods on @DBRef field with the qualifier isNull throws Exception
* [DATAMONGO-578] - pom version issues in 1.1.x branch
* [DATAMONGO-583] - Check if you are using for loop with a DBCursor
* [DATAMONGO-585] - Exception during authentication in multithreaded access
* [DATAMONGO-588] - MongoTemplate.insert does not initialize null versions to zero
* [DATAMONGO-600] - Issues with polymorphism of nested types
* [DATAMONGO-601] - CannotGetMongoDbConnectionException should not print password in logfile
** Improvement
* [DATAMONGO-573] - Move to Logback for test logging
* [DATAMONGO-580] - Polish BeanDefinitionParsers to avoid warnings in STS
** Task
* [DATAMONGO-81] - Create unit tests for exception translation in MongoTemplate
* [DATAMONGO-563] - Upgrade to MongoDB driver 2.9.2 as it fixes a serious regression introduced in 2.9.0
* [DATAMONGO-576] - Configure java.util.logging to reduce verbose test logging
* [DATAMONGO-590] - Clean up code in MongoTemplate
* [DATAMONGO-608] - Release 1.1.2
Changes in version 1.1.1.GA (2012-10-17) Changes in version 1.1.1.GA (2012-10-17)
---------------------------------------- ----------------------------------------

View File

@@ -1,5 +1,5 @@
Spring Data Document 1.0 Spring Data Document 1.1.2
Copyright (c) [2010-2011] SpringSource, a division of VMware, Inc. Copyright (c) [2010-2013] SpringSource, a division of VMware, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License"). This product is licensed to you under the Apache License, Version 2.0 (the "License").
You may not use this product except in compliance with the License. You may not use this product except in compliance with the License.