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 5a3fa9660..e427962cc 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
@@ -109,6 +109,7 @@ import com.mongodb.util.JSON;
* @author Graeme Rocher
* @author Mark Pollack
* @author Oliver Gierke
+ * @author Amol Nayak
*/
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
@@ -734,11 +735,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
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);
}
});
@@ -757,11 +760,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
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;
}
});
@@ -788,11 +793,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
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);
}
});
@@ -880,7 +887,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/**
* Returns a {@link Query} for the given entity by its id.
- *
+ *
* @param object must not be {@literal null}.
* @return
*/
@@ -1171,7 +1178,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/**
* Create the specified collection using the provided options
- *
+ *
* @param collectionName
* @param collectionOptions
* @return the collection that was created
@@ -1193,7 +1200,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter
*
* 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
@@ -1218,7 +1225,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* 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
@@ -1248,7 +1255,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter.
*
* 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
@@ -1287,7 +1294,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* The first document that matches the query is returned and also removed from the collection in the database.
*
* 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.
@@ -1334,7 +1341,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
/**
* Populates the id property of the saved object, if it's not set already.
- *
+ *
* @param savedObject
* @param id
*/
@@ -1387,7 +1394,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* 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
@@ -1510,9 +1517,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
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);
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
index dad91857f..293529c12 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.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.
@@ -39,6 +39,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
@@ -71,6 +72,7 @@ import com.mongodb.WriteResult;
*
* @author Oliver Gierke
* @author Thomas Risberg
+ * @author Amol Nayak
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
@@ -160,6 +162,112 @@ public class MongoTemplateTests {
mongoTemplate.updateFirst(q, u, Person.class);
}
+ /**
+ * @see DATAMONGO-480
+ */
+ @Test
+ public void throwsExceptionForDuplicateIds() {
+
+ MongoTemplate template = new MongoTemplate(factory);
+ template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
+
+ Person person = new Person(new ObjectId(), "Amol");
+ person.setAge(28);
+
+ template.insert(person);
+
+ try {
+ template.insert(person);
+ fail("Expected DataIntegrityViolationException!");
+ } catch (DataIntegrityViolationException e) {
+ assertThat(e.getMessage(), containsString("E11000 duplicate key error index: database.person.$_id_ dup key:"));
+ }
+ }
+
+ /**
+ * @see DATAMONGO-480
+ */
+ @Test
+ public void throwsExceptionForUpdateWithInvalidPushOperator() {
+
+ MongoTemplate template = new MongoTemplate(factory);
+ template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
+
+ ObjectId id = new ObjectId();
+ Person person = new Person(id, "Amol");
+ person.setAge(28);
+
+ template.insert(person);
+
+ try {
+
+ Query query = new Query(Criteria.where("firstName").is("Amol"));
+ Update upd = new Update().push("age", 29);
+ 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"));
+ }
+ }
+
+ /**
+ * @see DATAMONGO-480
+ */
+ @Test
+ public void throwsExceptionForIndexViolationIfConfigured() {
+
+ MongoTemplate template = new MongoTemplate(factory);
+ template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
+ template.indexOps(Person.class).ensureIndex(new Index().on("firstName", Order.DESCENDING).unique());
+
+ Person person = new Person(new ObjectId(), "Amol");
+ person.setAge(28);
+
+ template.save(person);
+
+ person = new Person(new ObjectId(), "Amol");
+ person.setAge(28);
+
+ try {
+ template.save(person);
+ fail("Expected DataIntegrityViolationException!");
+ } catch (DataIntegrityViolationException e) {
+ assertThat(e.getMessage(),
+ containsString("E11000 duplicate key error index: database.person.$firstName_-1 dup key:"));
+ }
+ }
+
+ /**
+ * @see DATAMONGO-480
+ */
+ @Test
+ public void rejectsDuplicateIdInInsertAll() {
+
+ MongoTemplate template = new MongoTemplate(factory);
+ template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
+
+ ObjectId id = new ObjectId();
+ Person person = new Person(id, "Amol");
+ person.setAge(28);
+
+ List records = new ArrayList();
+ records.add(person);
+ records.add(person);
+
+ try {
+ template.insertAll(records);
+ fail("Expected DataIntegrityViolationException!");
+ } catch (DataIntegrityViolationException e) {
+ assertThat(
+ e.getMessage(),
+ startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
+ }
+ }
+
@Test
public void testEnsureIndex() throws Exception {
@@ -190,7 +298,7 @@ public class MongoTemplateTests {
assertThat(dropDupes, is(true));
List indexInfoList = template.indexOps(Person.class).getIndexInfo();
- System.out.println(indexInfoList);
+
assertThat(indexInfoList.size(), is(2));
IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true));
@@ -932,7 +1040,7 @@ public class MongoTemplateTests {
DBRef first = new DBRef(factory.getDb(), "foo", new ObjectId());
DBRef second = new DBRef(factory.getDb(), "bar", new ObjectId());
- template.updateFirst(null, Update.update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class);
+ template.updateFirst(null, update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class);
}
class ClassWithDBRefs {
@@ -1095,7 +1203,7 @@ public class MongoTemplateTests {
template.save(second);
Query query = query(where("field").not().regex("Matthews"));
- System.out.println(query.getQueryObject());
+
List result = template.find(query, Sample.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).field, is("Beauford"));