diff --git a/README.md b/README.md
index 76fb0b09d4..479696797b 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,22 @@
-Spring Data - Document
+Spring Data MongoDB
======================
The primary goal of the [Spring Data](http://www.springsource.org/spring-data) project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
-As the name implies, the **Document** modules provides integration with document databases such as [MongoDB](http://www.mongodb.org/) and [CouchDB](http://couchdb.apache.org/).
+
+The Spring Data MongoDB aims to provide a familiar and consistent Spring-based programming model for for new datastores while retaining store-specific features and capabilities. The Spring Data MongoDB project provides integration with the MongoDB document database. Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB DBCollection and easily writing a Repository style data access layer
Getting Help
------------
-At this point your best bet is to look at the Look at the [JavaDocs](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/spring-data-mongodb/apidocs/) for MongoDB integration and corresponding and source code. For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80). If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects).
+For a comprehensive treatmet of all the Spring Data MongoDB features, please refer to the The [User Guide](http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/)
+
+The [JavaDocs](http://static.springsource.org/spring-data/data-mongodb/docs/current/api/) have extensive comments in them as well.
+
+The home page of [Spring Data MongoDB](http://www.springsource.org/spring-data/mongodb) contains links to articles and other resources.
-The [User Guide](http://static.springsource.org/spring-data/data-document/docs/1.0.0.BUILD-SNAPSHOT/reference/html/) (A work in progress).
+For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80).
+If you are new to Spring as well as to Spring Data, look for information about [Spring projects](http://www.springsource.org/projects).
Quick Start
@@ -137,11 +143,6 @@ This will register an object in the container named PersonRepository. You can u
}
-## CouchDB
-
-TBD
-
-
Contributing to Spring Data
---------------------------
diff --git a/spring-data-mongodb-parent/pom.xml b/spring-data-mongodb-parent/pom.xml
index 2386a000fb..88131bbad2 100644
--- a/spring-data-mongodb-parent/pom.xml
+++ b/spring-data-mongodb-parent/pom.xml
@@ -16,9 +16,8 @@
1.6.1
1.6.1
3.0.7.RELEASE
- 4.0.0.RELEASE
- [${org.springframework.version.30}, ${org.springframework.version.40})
- 1.3.2.BUILD-SNAPSHOT
+ 3.1.2.RELEASE
+ 1.4.0.BUILD-SNAPSHOT
1.6.11.RELEASE
true
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index d136285eff..e5fd0599ff 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -181,7 +181,7 @@
com.mysema.maven
maven-apt-plugin
- 1.0.2
+ 1.0.4
generate-test-sources
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
index 4547166f2c..6333d0ef6e 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
@@ -39,7 +39,7 @@
import com.mongodb.Mongo;
/**
- * Base class for Spring Data Mongo configuration using JavaConfig.
+ * Base class for Spring Data MongoDB configuration using JavaConfig.
*
* @author Mark Pollack
* @author Oliver Gierke
@@ -86,22 +86,26 @@ public MongoTemplate mongoTemplate() throws Exception {
@Bean
public SimpleMongoDbFactory mongoDbFactory() throws Exception {
- UserCredentials creadentials = getUserCredentials();
+ UserCredentials credentials = getUserCredentials();
- if (creadentials == null) {
+ if (credentials == null) {
return new SimpleMongoDbFactory(mongo(), getDatabaseName());
} else {
- return new SimpleMongoDbFactory(mongo(), getDatabaseName(), creadentials);
+ return new SimpleMongoDbFactory(mongo(), getDatabaseName(), credentials);
}
}
/**
- * Return the base package to scan for mapped {@link Document}s.
+ * Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
+ * class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
+ * {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is
+ * overriden to implement alternate behaviour.
*
- * @return
+ * @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
+ * entities.
*/
protected String getMappingBasePackage() {
- return null;
+ return getClass().getPackage().getName();
}
/**
@@ -127,7 +131,7 @@ public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
- mappingContext.afterPropertiesSet();
+ mappingContext.initialize();
return mappingContext;
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java
index dfb7e97914..8bfd4aaa6c 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java
@@ -48,6 +48,7 @@
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.data.annotation.Persistent;
+import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
@@ -166,27 +167,35 @@ private String potentiallyCreateMappingContext(Element element, ParserContext pa
BeanDefinition conversionsDefinition) {
String ctxRef = element.getAttribute("mapping-context-ref");
- if (!StringUtils.hasText(ctxRef)) {
- BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
- .genericBeanDefinition(MongoMappingContext.class);
- Set classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
- if (classesToAdd != null) {
- mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
- }
+ if (StringUtils.hasText(ctxRef)) {
+ return ctxRef;
+ }
- if (conversionsDefinition != null) {
- AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
- simpleTypesDefinition.setFactoryBeanName("customConversions");
- simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
+ BeanComponentDefinitionBuilder componentDefinitionBuilder = new BeanComponentDefinitionBuilder(element,
+ parserContext);
- mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
- }
+ BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(MongoMappingContext.class);
- parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
- ctxRef = MAPPING_CONTEXT;
+ Set classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
+ if (classesToAdd != null) {
+ mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
+ if (conversionsDefinition != null) {
+ AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
+ simpleTypesDefinition.setFactoryBeanName("customConversions");
+ simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
+
+ mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
+ }
+
+ parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
+ ctxRef = MAPPING_CONTEXT;
+
+ parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
+
return ctxRef;
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
index 4813a4494b..6e65a7c639 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 by the original author(s).
+ * Copyright 2011-2012 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,19 +15,19 @@
*/
package org.springframework.data.mongodb.config;
-import static org.springframework.data.mongodb.config.BeanNames.*;
-import static org.springframework.data.mongodb.config.ParsingUtils.*;
+import static org.springframework.data.config.ParsingUtils.*;
+import static org.springframework.data.mongodb.config.MongoParsingUtils.*;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.authentication.UserCredentials;
+import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.util.StringUtils;
@@ -44,19 +44,29 @@
*/
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
+ */
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
- String id = element.getAttribute("id");
- if (!StringUtils.hasText(id)) {
- id = DB_FACTORY;
- }
- return id;
+
+ String id = super.resolveId(element, definition, parserContext);
+ return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
+ */
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
+ Object source = parserContext.extractSource(element);
+
+ BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
+
String uri = element.getAttribute("uri");
String mongoRef = element.getAttribute("mongo-ref");
String dbname = element.getAttribute("dbname");
@@ -64,12 +74,11 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
// Common setup
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
- ParsingUtils.setPropertyValue(element, dbFactoryBuilder, "write-concern", "writeConcern");
+ setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern");
if (StringUtils.hasText(uri)) {
if (StringUtils.hasText(mongoRef) || StringUtils.hasText(dbname) || userCredentials != null) {
- parserContext.getReaderContext().error("Configure either Mongo URI or details individually!",
- parserContext.extractSource(element));
+ parserContext.getReaderContext().error("Configure either Mongo URI or details individually!", source);
}
dbFactoryBuilder.addConstructorArgValue(getMongoUri(uri));
@@ -77,19 +86,26 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
}
// Defaulting
- mongoRef = StringUtils.hasText(mongoRef) ? mongoRef : registerMongoBeanDefinition(element, parserContext);
- dbname = StringUtils.hasText(dbname) ? dbname : "db";
+ if (StringUtils.hasText(mongoRef)) {
+ dbFactoryBuilder.addConstructorArgReference(mongoRef);
+ } else {
+ dbFactoryBuilder.addConstructorArgValue(registerMongoBeanDefinition(element, parserContext));
+ }
- dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef));
+ dbname = StringUtils.hasText(dbname) ? dbname : "db";
dbFactoryBuilder.addConstructorArgValue(dbname);
if (userCredentials != null) {
dbFactoryBuilder.addConstructorArgValue(userCredentials);
}
- ParsingUtils.registerWriteConcernPropertyEditor(parserContext.getRegistry());
+ BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
+
+ BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
+ parserContext.registerBeanComponent(component);
- return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element);
+ return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY)
+ .getBeanDefinition();
}
/**
@@ -100,14 +116,13 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
* @param parserContext must not be {@literal null}.
* @return
*/
- private String registerMongoBeanDefinition(Element element, ParserContext parserContext) {
+ private BeanDefinition registerMongoBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
- ParsingUtils.setPropertyValue(element, mongoBuilder, "host");
- ParsingUtils.setPropertyValue(element, mongoBuilder, "port");
+ setPropertyValue(mongoBuilder, element, "host");
+ setPropertyValue(mongoBuilder, element, "port");
- return BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(),
- parserContext.getRegistry());
+ return getSourceBeanDefinition(mongoBuilder, parserContext, element);
}
/**
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
index 4eb27dee57..a01de78780 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java
@@ -16,7 +16,9 @@
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
-import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigParser;
+import org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension;
+import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
+import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB based repositories.
@@ -32,7 +34,10 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
*/
public void init() {
- registerBeanDefinitionParser("repositories", new MongoRepositoryConfigParser());
+ RepositoryConfigurationExtension extension = new MongoRepositoryConfigurationExtension();
+ RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension);
+
+ registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser);
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
registerBeanDefinitionParser("mongo", new MongoParser());
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
index 8c8be401ee..f03f9c697c 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 the original author or authors.
+ * Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.springframework.data.mongodb.config;
import java.util.Map;
-import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedMap;
-import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.data.config.BeanComponentDefinitionBuilder;
+import org.springframework.data.config.ParsingUtils;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -35,54 +35,59 @@
* Parser for <mongo;gt; definitions.
*
* @author Mark Pollack
+ * @author Oliver Gierke
*/
-public class MongoParser extends AbstractSingleBeanDefinitionParser {
+public class MongoParser implements BeanDefinitionParser {
- @Override
- protected Class> getBeanClass(Element element) {
- return MongoFactoryBean.class;
- }
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
+ */
+ public BeanDefinition parse(Element element, ParserContext parserContext) {
+
+ Object source = parserContext.extractSource(element);
+ String id = element.getAttribute("id");
- @Override
- protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+ BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
- ParsingUtils.setPropertyValue(element, builder, "port", "port");
- ParsingUtils.setPropertyValue(element, builder, "host", "host");
- ParsingUtils.setPropertyValue(element, builder, "write-concern", "writeConcern");
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
+ ParsingUtils.setPropertyValue(builder, element, "port", "port");
+ ParsingUtils.setPropertyValue(builder, element, "host", "host");
+ ParsingUtils.setPropertyValue(builder, element, "write-concern", "writeConcern");
- ParsingUtils.parseMongoOptions(element, builder);
- ParsingUtils.parseReplicaSet(element, builder);
+ MongoParsingUtils.parseMongoOptions(element, builder);
+ MongoParsingUtils.parseReplicaSet(element, builder);
- registerServerAddressPropertyEditor(parserContext.getRegistry());
- ParsingUtils.registerWriteConcernPropertyEditor(parserContext.getRegistry());
+ String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO;
+ parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
+
+ BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
+ parserContext.registerBeanComponent(mongoComponent);
+ BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor());
+ parserContext.registerBeanComponent(serverAddressPropertyEditor);
+ BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
+ .getWriteConcernPropertyEditorBuilder());
+ parserContext.registerBeanComponent(writeConcernPropertyEditor);
+
+ parserContext.popAndRegisterContainingComponent();
+
+ return mongoComponent.getBeanDefinition();
}
/**
* One should only register one bean definition but want to have the convenience of using
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
* container.
- *
- * @param parserContext the ParserContext to
*/
- private void registerServerAddressPropertyEditor(BeanDefinitionRegistry registry) {
+ private BeanDefinitionBuilder registerServerAddressPropertyEditor() {
- BeanDefinitionBuilder customEditorConfigurer = BeanDefinitionBuilder
- .genericBeanDefinition(CustomEditorConfigurer.class);
Map customEditors = new ManagedMap();
customEditors.put("com.mongodb.ServerAddress[]",
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
- customEditorConfigurer.addPropertyValue("customEditors", customEditors);
- BeanDefinitionReaderUtils.registerWithGeneratedName(customEditorConfigurer.getBeanDefinition(), registry);
- }
- @Override
- protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
- throws BeanDefinitionStoreException {
- String name = super.resolveId(element, definition, parserContext);
- if (!StringUtils.hasText(name)) {
- name = "mongo";
- }
- return name;
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
+ builder.addPropertyValue("customEditors", customEditors);
+ return builder;
}
-}
\ No newline at end of file
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java
new file mode 100644
index 0000000000..6613f7066f
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2011-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb.config;
+
+import static org.springframework.data.config.ParsingUtils.*;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.CustomEditorConfigurer;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Utility methods for {@link BeanDefinitionParser} implementations for MongoDB.
+ *
+ * @author Mark Pollack
+ * @author Oliver Gierke
+ */
+abstract class MongoParsingUtils {
+
+ private MongoParsingUtils() {
+
+ }
+
+ /**
+ * Parses the mongo replica-set element.
+ *
+ * @param parserContext the parser context
+ * @param element the mongo element
+ * @param mongoBuilder the bean definition builder to populate
+ * @return
+ */
+ static void parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) {
+ setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds");
+ }
+
+ /**
+ * Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
+ *
+ * @return true if parsing actually occured, false otherwise
+ */
+ static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
+ Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
+ if (optionsElement == null) {
+ return false;
+ }
+
+ BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(MongoOptionsFactoryBean.class);
+
+ setPropertyValue(optionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
+ setPropertyValue(optionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
+ "threadsAllowedToBlockForConnectionMultiplier");
+ setPropertyValue(optionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
+ setPropertyValue(optionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
+ setPropertyValue(optionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
+ setPropertyValue(optionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
+ setPropertyValue(optionsDefBuilder, optionsElement, "auto-connect-retry", "autoConnectRetry");
+ setPropertyValue(optionsDefBuilder, optionsElement, "max-auto-connect-retry-time", "maxAutoConnectRetryTime");
+ setPropertyValue(optionsDefBuilder, optionsElement, "write-number", "writeNumber");
+ setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
+ setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
+ setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
+
+ mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
+ return true;
+ }
+
+ /**
+ * Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
+ * {@link WriteConcernPropertyEditor}.
+ *
+ * @return
+ */
+ static BeanDefinitionBuilder getWriteConcernPropertyEditorBuilder() {
+
+ Map> customEditors = new ManagedMap>();
+ customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class);
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
+ builder.addPropertyValue("customEditors", customEditors);
+
+ return builder;
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java
deleted file mode 100644
index 36a2411d35..0000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ParsingUtils.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2011 by the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.data.mongodb.config;
-
-import java.util.Map;
-
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.CustomEditorConfigurer;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.ManagedMap;
-import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-import org.springframework.util.xml.DomUtils;
-import org.w3c.dom.Element;
-
-abstract class ParsingUtils {
-
- /**
- * Parses the mongo replica-set element.
- *
- * @param parserContext the parser context
- * @param element the mongo element
- * @param mongoBuilder the bean definition builder to populate
- * @return true if parsing actually occured, false otherwise
- */
- static boolean parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) {
-
- String replicaSetString = element.getAttribute("replica-set");
- if (StringUtils.hasText(replicaSetString)) {
- mongoBuilder.addPropertyValue("replicaSetSeeds", replicaSetString);
- }
- return true;
-
- }
-
- /**
- * Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
- *
- * @return true if parsing actually occured, false otherwise
- */
- static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
- Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
- if (optionsElement == null) {
- return false;
- }
-
- BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
- .genericBeanDefinition(MongoOptionsFactoryBean.class);
-
- setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost");
- setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier",
- "threadsAllowedToBlockForConnectionMultiplier");
- setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime");
- setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout");
- setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout");
- setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive");
- setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry");
- setPropertyValue(optionsElement, optionsDefBuilder, "max-auto-connect-retry-time", "maxAutoConnectRetryTime");
- setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber");
- setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout");
- setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync");
- setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk");
-
- mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
- return true;
- }
-
- static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) {
- String attr = element.getAttribute(attrName);
- if (StringUtils.hasText(attr)) {
- builder.addPropertyValue(propertyName, attr);
- }
- }
-
- /**
- * Sets the property with the given attribute name on the given {@link BeanDefinitionBuilder} to the value of the
- * attribute with the given name.
- *
- * @param element must not be {@literal null}.
- * @param builder must not be {@literal null}.
- * @param attrName must not be {@literal null} or empty.
- */
- static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName) {
- String attr = element.getAttribute(attrName);
- if (StringUtils.hasText(attr)) {
- builder.addPropertyValue(attrName, attr);
- }
- }
-
- /**
- * Returns the {@link BeanDefinition} built by the given {@link BeanDefinitionBuilder} enriched with source
- * information derived from the given {@link Element}.
- *
- * @param builder must not be {@literal null}.
- * @param context must not be {@literal null}.
- * @param element must not be {@literal null}.
- * @return
- */
- static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, ParserContext context,
- Element element) {
- AbstractBeanDefinition definition = builder.getBeanDefinition();
- definition.setSource(context.extractSource(element));
- return definition;
- }
-
- /**
- * Registers a {@link WriteConcernPropertyEditor} in the given {@link BeanDefinitionRegistry}.
- *
- * @param registry must not be {@literal null}.
- */
- static void registerWriteConcernPropertyEditor(BeanDefinitionRegistry registry) {
-
- Assert.notNull(registry);
-
- BeanDefinitionBuilder customEditorConfigurer = BeanDefinitionBuilder
- .genericBeanDefinition(CustomEditorConfigurer.class);
- Map> customEditors = new ManagedMap>();
- customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class);
- customEditorConfigurer.addPropertyValue("customEditors", customEditors);
- BeanDefinitionReaderUtils.registerWithGeneratedName(customEditorConfigurer.getBeanDefinition(), registry);
- }
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
index 0b2dea58e4..3cf7304ddb 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
@@ -657,6 +657,8 @@ T findAndModify(Query query, Update update, FindAndModifyOptions options, Cl
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateFirst(Query query, Update update, Class> entityClass);
+
+ WriteResult updateFirst(Query query, Object object, Class> entityClass);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index 7ff775bb44..84eec1615b 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -15,10 +15,10 @@
*/
package org.springframework.data.mongodb.core;
+import static org.springframework.data.mongodb.core.SerializationUtils.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -44,6 +44,7 @@
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.mapping.PersistentEntity;
@@ -106,6 +107,7 @@
* @author Graeme Rocher
* @author Mark Pollack
* @author Oliver Gierke
+ * @author Amol Nayak
*/
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
@@ -206,7 +208,6 @@ public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverte
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
}
}
-
}
/**
@@ -331,11 +332,12 @@ protected void executeQuery(Query query, String collectionName, DocumentCallback
Assert.notNull(query);
DBObject queryObject = query.getQueryObject();
+ DBObject sortObject = query.getSortObject();
DBObject fieldsObject = query.getFieldsObject();
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("find using query: " + queryObject + " fields: " + fieldsObject + " in collection: "
- + collectionName);
+ LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: $s",
+ serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
}
this.executeQueryInternal(new FindCallback(queryObject, fieldsObject), preparer, dch, collectionName);
@@ -702,7 +704,26 @@ public void save(Object objectToSave) {
}
public void save(Object objectToSave, String collectionName) {
- doSave(collectionName, objectToSave, this.mongoConverter);
+ MongoPersistentEntity> mongoPersistentEntity = getPersistentEntity(objectToSave.getClass());
+ if(mongoPersistentEntity.hasVersion()){
+ BeanWrapper, Object> beanWrapper = BeanWrapper.create(objectToSave, null);
+ Object id = beanWrapper.getProperty(mongoPersistentEntity.getIdProperty());
+ if(id == null){
+ beanWrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
+ doSave(collectionName, objectToSave, this.mongoConverter);
+ } else {
+ updateFirst( getUpdateVersionQuery(id,
+ beanWrapper.getProperty(mongoPersistentEntity.getVersionProperty()),mongoPersistentEntity),
+ objectToSave, objectToSave.getClass());
+ }
+ } else {
+ doSave(collectionName, objectToSave, this.mongoConverter);
+ }
+ }
+
+ private Query getUpdateVersionQuery(Object id, Object version,MongoPersistentEntity> mongoPersistentEntity) {
+ return new Query( Criteria.where(mongoPersistentEntity.getIdProperty().getName()).is(id)
+ .and(mongoPersistentEntity.getVersionProperty().getName()).is(version));
}
protected void doSave(String collectionName, T objectToSave, MongoWriter writer) {
@@ -730,11 +751,13 @@ public Object doInCollection(DBCollection collection) throws MongoException, Dat
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName,
entityClass, dbDoc, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
+ WriteResult wr;
if (writeConcernToUse == null) {
- collection.insert(dbDoc);
+ wr = collection.insert(dbDoc);
} else {
- collection.insert(dbDoc, writeConcernToUse);
+ wr = collection.insert(dbDoc, writeConcernToUse);
}
+ handleAnyWriteResultErrors(wr, dbDoc, "insert");
return dbDoc.get(ID);
}
});
@@ -753,11 +776,13 @@ public Void doInCollection(DBCollection collection) throws MongoException, DataA
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null,
null, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
+ WriteResult wr;
if (writeConcernToUse == null) {
- collection.insert(dbDocList);
+ wr = collection.insert(dbDocList);
} else {
- collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
+ wr = collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
}
+ handleAnyWriteResultErrors(wr, null, "insert_list");
return null;
}
});
@@ -784,11 +809,13 @@ public Object doInCollection(DBCollection collection) throws MongoException, Dat
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass,
dbDoc, null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
+ WriteResult wr;
if (writeConcernToUse == null) {
- collection.save(dbDoc);
+ wr = collection.save(dbDoc);
} else {
- collection.save(dbDoc, writeConcernToUse);
+ wr = collection.save(dbDoc, writeConcernToUse);
}
+ handleAnyWriteResultErrors(wr, dbDoc, "save");
return dbDoc.get(ID);
}
});
@@ -809,6 +836,18 @@ public WriteResult updateFirst(Query query, Update update, Class> entityClass)
public WriteResult updateFirst(final Query query, final Update update, final String collectionName) {
return doUpdate(collectionName, query, update, null, false, false);
}
+
+ public WriteResult updateFirst(final Query query, final Object object,
+ Class> entityClass) {
+
+ BasicDBObject dbObject = new BasicDBObject();
+ this.mongoConverter.write(object, dbObject);
+
+ return doUpdate(determineCollectionName(entityClass), query,
+ Update.fromDBObject(dbObject, ID,
+ getPersistentEntity(entityClass).getVersionProperty()
+ .getName()), entityClass, false, false);
+ }
public WriteResult updateMulti(Query query, Update update, Class> entityClass) {
return doUpdate(determineCollectionName(entityClass), query, update, entityClass, false, true);
@@ -828,9 +867,14 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException
DBObject queryObj = query == null ? new BasicDBObject()
: mapper.getMappedObject(query.getQueryObject(), entity);
+
+ if(null != update && null != entity && entity.hasVersion()) {
+ update.inc(entity.getVersionProperty().getName(), 1);
+ }
+
DBObject updateObj = update == null ? new BasicDBObject() : mapper.getMappedObject(update.getUpdateObject(),
entity);
-
+
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("calling update using query: " + queryObj + " and update: " + updateObj + " in collection: "
+ collectionName);
@@ -845,6 +889,11 @@ public WriteResult doInCollection(DBCollection collection) throws MongoException
} else {
wr = collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
}
+ if(null != entity && entity.hasVersion() && !multi){
+ if(wr.getN() == 0){
+ throw new OptimisticLockingFailureException("Optimistic lock exception on saveing entity: "+updateObj.toMap().toString());
+ }
+ }
handleAnyWriteResultErrors(wr, queryObj, "update with '" + updateObj + "'");
return wr;
}
@@ -873,7 +922,7 @@ public void remove(Object object, String collection) {
/**
* Returns a {@link Query} for the given entity by its id.
- *
+ *
* @param object must not be {@literal null}.
* @return
*/
@@ -991,26 +1040,15 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName
LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc
+ "], reduceFunction [" + reduceFunc + "]");
}
- CommandResult commandResult = null;
- try {
- if (command.getOutputType() == MapReduceCommand.OutputType.INLINE) {
- commandResult = executeCommand(commandObject, getDb().getOptions());
- } else {
- commandResult = executeCommand(commandObject);
- }
- commandResult.throwOnError();
- } catch (RuntimeException ex) {
- this.potentiallyConvertRuntimeException(ex);
- }
- String error = commandResult.getErrorMessage();
- if (error != null) {
- throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = "
- + commandObject);
- }
+
+ CommandResult commandResult = command.getOutputType() == MapReduceCommand.OutputType.INLINE ? executeCommand(
+ commandObject, getDb().getOptions()) : executeCommand(commandObject);
+ handleCommandError(commandResult, commandObject);
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("MapReduce command result = [" + commandResult + "]");
+ LOGGER.debug(String.format("MapReduce command result = [%s]", serializeToJsonSafely(commandObject)));
}
+
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
List mappedResults = new ArrayList();
DbObjectCallback callback = new ReadDbObjectCallback(mongoConverter, entityClass);
@@ -1035,7 +1073,7 @@ public GroupByResults group(Criteria criteria, String inputCollectionName
if (criteria == null) {
dbo.put("cond", null);
} else {
- dbo.put("cond", criteria.getCriteriaObject());
+ dbo.put("cond", mapper.getMappedObject(criteria.getCriteriaObject(), null));
}
// If initial document was a JavaScript string, potentially loaded by Spring's Resource abstraction, load it and
// convert to DBObject
@@ -1061,21 +1099,12 @@ public GroupByResults group(Criteria criteria, String inputCollectionName
DBObject commandObject = new BasicDBObject("group", dbo);
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Executing Group with DBObject [" + commandObject.toString() + "]");
- }
- CommandResult commandResult = null;
- try {
- commandResult = executeCommand(commandObject, getDb().getOptions());
- commandResult.throwOnError();
- } catch (RuntimeException ex) {
- this.potentiallyConvertRuntimeException(ex);
- }
- String error = commandResult.getErrorMessage();
- if (error != null) {
- throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = "
- + commandObject);
+ LOGGER.debug(String.format("Executing Group with DBObject [%s]", serializeToJsonSafely(commandObject)));
}
+ CommandResult commandResult = executeCommand(commandObject, getDb().getOptions());
+ handleCommandError(commandResult, commandObject);
+
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Group command result = [" + commandResult + "]");
}
@@ -1182,7 +1211,7 @@ protected void maybeEmitEvent(MongoMappingEvent event) {
/**
* Create the specified collection using the provided options
- *
+ *
* @param collectionName
* @param collectionOptions
* @return the collection that was created
@@ -1204,7 +1233,7 @@ public DBCollection doInDB(DB db) throws MongoException, DataAccessException {
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter
*
* The query document is specified as a standard DBObject and so is the fields specification.
- *
+ *
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1229,7 +1258,7 @@ protected T doFindOne(String collectionName, DBObject query, DBObject fields
* The query document is specified as a standard DBObject and so is the fields specification.
*
* Can be overridden by subclasses.
- *
+ *
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1246,11 +1275,14 @@ protected List doFind(String collectionName, DBObject query, DBObject fie
protected List doFind(String collectionName, DBObject query, DBObject fields, Class entityClass,
CursorPreparer preparer, DbObjectCallback objectCallback) {
+
MongoPersistentEntity> entity = mappingContext.getPersistentEntity(entityClass);
+
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("find using query: " + query + " fields: " + fields + " for class: " + entityClass
- + " in collection: " + collectionName);
+ LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
+ serializeToJsonSafely(query), fields, entityClass, collectionName));
}
+
return executeFindMultiInternal(new FindCallback(mapper.getMappedObject(query, entity), fields), preparer,
objectCallback, collectionName);
}
@@ -1259,7 +1291,7 @@ protected List doFind(String collectionName, DBObject query, DBObject
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter.
*
* The query document is specified as a standard DBObject and so is the fields specification.
- *
+ *
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param fields the document that specifies the fields to be returned
@@ -1298,7 +1330,7 @@ protected DBObject convertToDbObject(CollectionOptions collectionOptions) {
* The first document that matches the query is returned and also removed from the collection in the database.
*
* The query document is specified as a standard DBObject and so is the fields specification.
- *
+ *
* @param collectionName name of the collection to retrieve the objects from
* @param query the query document that specifies the criteria used to find a record
* @param entityClass the parameterized type of the returned list.
@@ -1345,7 +1377,7 @@ protected T doFindAndModify(String collectionName, DBObject query, DBObject
/**
* Populates the id property of the saved object, if it's not set already.
- *
+ *
* @param savedObject
* @param id
*/
@@ -1364,21 +1396,13 @@ protected void populateIdIfNecessary(Object savedObject, Object id) {
ConversionService conversionService = mongoConverter.getConversionService();
BeanWrapper, Object> wrapper = BeanWrapper.create(savedObject, conversionService);
- try {
+ Object idValue = wrapper.getProperty(idProp, idProp.getType(), true);
- Object idValue = wrapper.getProperty(idProp);
-
- if (idValue != null) {
- return;
- }
-
- wrapper.setProperty(idProp, id);
-
- } catch (IllegalAccessException e) {
- throw new MappingException(e.getMessage(), e);
- } catch (InvocationTargetException e) {
- throw new MappingException(e.getMessage(), e);
+ if (idValue != null) {
+ return;
}
+
+ wrapper.setProperty(idProp, id);
}
private DBCollection getAndPrepareCollection(DB db, String collectionName) {
@@ -1398,7 +1422,7 @@ private DBCollection getAndPrepareCollection(DB db, String collectionName) {
* Execute the given {@link ConnectionCallback} for a {@link DBObject}.
* Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.
*
- *
+ *
* @param
* @param collectionCallback the callback to retrieve the {@link DBObject} with
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
@@ -1521,9 +1545,16 @@ protected void handleAnyWriteResultErrors(WriteResult wr, DBObject query, String
String error = wr.getError();
if (error != null) {
-
- String message = String.format("Execution of %s%s failed: %s", operation, query == null ? "" : "' using '"
- + query.toString() + "' query", error);
+ String message;
+ if (operation.equals("insert") || operation.equals("save")) {
+ // assuming the insert operations will begin with insert string
+ message = String.format("Insert/Save for %s failed: %s", query, error);
+ } else if (operation.equals("insert_list")) {
+ message = String.format("Insert list failed: %s", error);
+ } else {
+ message = String.format("Execution of %s%s failed: %s", operation,
+ query == null ? "" : "' using '" + query.toString() + "' query", error);
+ }
if (WriteResultChecking.EXCEPTION == this.writeResultChecking) {
throw new DataIntegrityViolationException(message);
@@ -1546,6 +1577,27 @@ private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex)
return resolved == null ? ex : resolved;
}
+ /**
+ * Inspects the given {@link CommandResult} for erros and potentially throws an
+ * {@link InvalidDataAccessApiUsageException} for that error.
+ *
+ * @param result must not be {@literal null}.
+ * @param source must not be {@literal null}.
+ */
+ private void handleCommandError(CommandResult result, DBObject source) {
+
+ try {
+ result.throwOnError();
+ } catch (MongoException ex) {
+
+ String error = result.getErrorMessage();
+ error = error == null ? "NO MESSAGE" : error;
+
+ throw new InvalidDataAccessApiUsageException("Command execution failed: Error [" + error + "], Command = "
+ + source, ex);
+ }
+ }
+
private static final MongoConverter getDefaultMongoConverter(MongoDbFactory factory) {
MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
converter.afterPropertiesSet();
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java
index ada9514750..40354e1ecd 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java
@@ -223,7 +223,7 @@ public Class> getCustomWriteTarget(Class> source) {
/**
* Returns the target type we can write an onject of the given source type to. The returned type might be a subclass
- * oth the given expected type though. If {@code expexctedTargetType} is {@literal null} we will simply return the
+ * oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the
* first target type matching or {@literal null} if no conversion can be found.
*
* @param source must not be {@literal null}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
index e5d90c5a39..359c4cd5d2 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
@@ -15,7 +15,6 @@
*/
package org.springframework.data.mongodb.core.convert;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -253,13 +252,9 @@ public void doWithPersistentProperty(MongoPersistentProperty prop) {
public void doWithAssociation(Association association) {
MongoPersistentProperty inverseProp = association.getInverse();
Object obj = getValueInternal(inverseProp, dbo, evaluator, result);
- try {
- wrapper.setProperty(inverseProp, obj);
- } catch (IllegalAccessException e) {
- throw new MappingException(e.getMessage(), e);
- } catch (InvocationTargetException e) {
- throw new MappingException(e.getMessage(), e);
- }
+
+ wrapper.setProperty(inverseProp, obj);
+
}
});
@@ -676,6 +671,10 @@ protected DBRef createDBRef(Object target, org.springframework.data.mongodb.core
Assert.notNull(target);
+ if (target instanceof DBRef) {
+ return (DBRef) target;
+ }
+
MongoPersistentEntity> targetEntity = mappingContext.getPersistentEntity(target.getClass());
if (null == targetEntity) {
@@ -713,18 +712,19 @@ protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, Sp
*
* @param targetType must not be {@literal null}.
* @param sourceValue must not be {@literal null}.
- * @return the converted {@link Collections}, will never be {@literal null}.
+ * @return the converted {@link Collection} or array, will never be {@literal null}.
*/
@SuppressWarnings("unchecked")
- private Collection> readCollectionOrArray(TypeInformation> targetType, BasicDBList sourceValue, Object parent) {
+ private Object readCollectionOrArray(TypeInformation> targetType, BasicDBList sourceValue, Object parent) {
Assert.notNull(targetType);
+ Class> collectionType = targetType.getType();
+
if (sourceValue.isEmpty()) {
- return new HashSet