From 0cdec56a27c5596d8959c0e53381ae0270d755b5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 15 Apr 2013 17:03:35 +0200 Subject: [PATCH] DATAMONGO-651 - MongoTemplate now throws Mongo-specific exception with WriteResult. If the WriteResultChecking is set to EXCEPTION on a MongoTemplate, we now throw a Mongo-specific exception that captures both the WriteResult and MongoActionOperation for further evaluation. --- .../MongoDataIntegrityViolationException.java | 72 +++++++++++++++++++ .../data/mongodb/core/MongoTemplate.java | 4 +- .../data/mongodb/core/MongoTemplateTests.java | 29 +++++++- 3 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDataIntegrityViolationException.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDataIntegrityViolationException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDataIntegrityViolationException.java new file mode 100644 index 000000000..cb2f64b91 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDataIntegrityViolationException.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb; + +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.mongodb.core.MongoActionOperation; +import org.springframework.util.Assert; + +import com.mongodb.WriteResult; + +/** + * Mongo-specific {@link DataIntegrityViolationException}. + * + * @author Oliver Gierke + */ +public class MongoDataIntegrityViolationException extends DataIntegrityViolationException { + + private static final long serialVersionUID = -186980521176764046L; + + private final WriteResult writeResult; + private final MongoActionOperation actionOperation; + + /** + * Creates a new {@link MongoDataIntegrityViolationException} using the given message and {@link WriteResult}. + * + * @param message the exception message + * @param writeResult the {@link WriteResult} that causes the exception, must not be {@literal null}. + * @param actionOperation the {@link MongoActionOperation} that caused the exception, must not be {@literal null}. + */ + public MongoDataIntegrityViolationException(String message, WriteResult writeResult, + MongoActionOperation actionOperation) { + + super(message); + + Assert.notNull(writeResult, "WriteResult must not be null!"); + Assert.notNull(actionOperation, "MongoActionOperation must not be null!"); + + this.writeResult = writeResult; + this.actionOperation = actionOperation; + } + + /** + * Returns the {@link WriteResult} that caused the exception. + * + * @return the writeResult + */ + public WriteResult getWriteResult() { + return writeResult; + } + + /** + * Returns the {@link MongoActionOperation} in which the current exception occured. + * + * @return the actionOperation + */ + public MongoActionOperation getActionOperation() { + return actionOperation; + } +} 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 107074a5a..d8833765c 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 @@ -44,7 +44,6 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.authentication.UserCredentials; @@ -53,6 +52,7 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.BeanWrapper; import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mongodb.MongoDataIntegrityViolationException; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.convert.MongoConverter; @@ -1647,7 +1647,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { } if (writeResultChecking == WriteResultChecking.EXCEPTION) { - throw new DataIntegrityViolationException(message); + throw new MongoDataIntegrityViolationException(message, writeResult, operation); } else { LOGGER.error(message); return; 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 bc6bc21f3..6178ffd40 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 @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import static org.mockito.Mockito.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.core.query.Update.*; @@ -30,6 +31,7 @@ import java.util.List; import java.util.Map; import org.bson.types.ObjectId; +import org.hamcrest.CoreMatchers; import org.joda.time.DateTime; import org.junit.After; import org.junit.Assert; @@ -50,6 +52,7 @@ import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.annotation.Version; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; +import org.springframework.data.mongodb.MongoDataIntegrityViolationException; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.convert.CustomConversions; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; @@ -275,7 +278,8 @@ public class MongoTemplateTests { } catch (DataIntegrityViolationException e) { assertThat( e.getMessage(), - startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId")); + CoreMatchers + .startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId")); } } @@ -1570,6 +1574,29 @@ public class MongoTemplateTests { assertThat(person.getFirstName(), is(nullValue())); } + /** + * @see DATAMONGO-651 + */ + @Test + public void throwsMongoSpecificExceptionForDataIntegrityViolations() { + + WriteResult result = mock(WriteResult.class); + when(result.getError()).thenReturn("ERROR"); + + MongoActionOperation operation = MongoActionOperation.INSERT; + + MongoTemplate mongoTemplate = new MongoTemplate(factory); + mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION); + + try { + mongoTemplate.handleAnyWriteResultErrors(result, null, operation); + fail("Expected MonogoDataIntegrityViolationException!"); + } catch (MongoDataIntegrityViolationException o_O) { + assertThat(o_O.getActionOperation(), is(operation)); + assertThat(o_O.getWriteResult(), is(result)); + } + } + static class MyId { String first;