Compare commits
3 Commits
4.0.0-M2
...
issue/DATA
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e7c37d646 | ||
|
|
9a2bc7d004 | ||
|
|
85d48f054c |
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0.DATAMONGO-2073-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0.DATAMONGO-2073-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0.DATAMONGO-2073-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0.DATAMONGO-2073-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* https://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.TransientDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link TransientDataAccessException} specific to MongoDB {@link com.mongodb.session.ClientSession} related data
|
||||
* access failures such as reading data using an already closed session.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public class TransientClientSessionException extends TransientMongoDbException {
|
||||
|
||||
/**
|
||||
* Constructor for {@link TransientClientSessionException}.
|
||||
*
|
||||
* @param msg the detail message. Can be {@literal null}.
|
||||
* @param cause the root cause. Can be {@literal null}.
|
||||
*/
|
||||
public TransientClientSessionException(@Nullable String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* https://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.TransientDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Root of the hierarchy of MongoDB specific data access exceptions that are considered transient such as
|
||||
* {@link com.mongodb.MongoException MongoExceptions} carrying {@link com.mongodb.MongoException#hasErrorLabel(String)
|
||||
* specific labels}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public class TransientMongoDbException extends TransientDataAccessException {
|
||||
|
||||
/**
|
||||
* Constructor for {@link TransientMongoDbException}.
|
||||
*
|
||||
* @param msg the detail message. Can be {@literal null}.
|
||||
* @param cause the root cause. Can be {@literal null}.
|
||||
*/
|
||||
public TransientMongoDbException(String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bson.BsonInvalidOperationException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -29,9 +28,11 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.MongoTransactionException;
|
||||
import org.springframework.data.mongodb.TransientClientSessionException;
|
||||
import org.springframework.data.mongodb.TransientMongoDbException;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -39,7 +40,6 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.mongodb.MongoBulkWriteException;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.MongoServerException;
|
||||
import com.mongodb.MongoSocketException;
|
||||
import com.mongodb.bulk.BulkWriteError;
|
||||
|
||||
@@ -75,6 +75,22 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
@Nullable
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
|
||||
DataAccessException translatedException = doTranslateException(ex);
|
||||
if (translatedException == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Translated exceptions that per se are not be recoverable (eg. WriteConflicts), might still be transient inside a
|
||||
// transaction. Let's wrap those.
|
||||
return (isTransientFailure(ex) && !(translatedException instanceof TransientDataAccessException))
|
||||
? new TransientMongoDbException(ex.getMessage(), translatedException)
|
||||
: translatedException;
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
DataAccessException doTranslateException(RuntimeException ex) {
|
||||
|
||||
// Check for well-known MongoException subclasses.
|
||||
|
||||
if (ex instanceof BsonInvalidOperationException) {
|
||||
@@ -101,13 +117,13 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
|
||||
if (DATA_INTEGRITY_EXCEPTIONS.contains(exception)) {
|
||||
|
||||
if (ex instanceof MongoServerException) {
|
||||
if (((MongoServerException) ex).getCode() == 11000) {
|
||||
if (ex instanceof MongoException) {
|
||||
if (MongoDbErrorCodes.isDataDuplicateKeyError(ex)) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof MongoBulkWriteException) {
|
||||
for (BulkWriteError x : ((MongoBulkWriteException) ex).getWriteErrors()) {
|
||||
if (x.getCode() == 11000) {
|
||||
for (BulkWriteError writeError : ((MongoBulkWriteException) ex).getWriteErrors()) {
|
||||
if (MongoDbErrorCodes.isDuplicateKeyCode(writeError.getCode())) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
@@ -120,21 +136,31 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
// All other MongoExceptions
|
||||
if (ex instanceof MongoException) {
|
||||
|
||||
int code = ((MongoException) ex).getCode();
|
||||
MongoException mongoException = (MongoException) ex;
|
||||
|
||||
if (MongoDbErrorCodes.isDuplicateKeyCode(code)) {
|
||||
if (MongoDbErrorCodes.isDuplicateKeyError(mongoException)) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isDataAccessResourceFailureCode(code)) {
|
||||
}
|
||||
if (MongoDbErrorCodes.isDataAccessResourceError(mongoException)) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isInvalidDataAccessApiUsageCode(code) || code == 10003 || code == 12001
|
||||
|| code == 12010 || code == 12011 || code == 12012) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isPermissionDeniedCode(code)) {
|
||||
}
|
||||
|
||||
{
|
||||
int code = mongoException.getCode();
|
||||
if (MongoDbErrorCodes.isInvalidDataAccessApiUsageError(mongoException) || code == 12001 || code == 12010
|
||||
|| code == 12011 || code == 12012) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
if (MongoDbErrorCodes.isPermissionDeniedError(mongoException)) {
|
||||
return new PermissionDeniedDataAccessException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isClientSessionFailureCode(code)) {
|
||||
return new ClientSessionException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isTransactionFailureCode(code)) {
|
||||
return new MongoTransactionException(ex.getMessage(), ex);
|
||||
}
|
||||
if (MongoDbErrorCodes.isDataIntegrityViolationError(mongoException)) {
|
||||
return new DataIntegrityViolationException(mongoException.getMessage(), mongoException);
|
||||
}
|
||||
if (MongoDbErrorCodes.isClientSessionFailure(mongoException)) {
|
||||
return isTransientFailure(mongoException) ? new TransientClientSessionException(ex.getMessage(), ex)
|
||||
: new ClientSessionException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return new UncategorizedMongoDbException(ex.getMessage(), ex);
|
||||
@@ -155,4 +181,25 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
// that translation should not occur.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given exception holds an error label indicating a transient failure.
|
||||
*
|
||||
* @param e
|
||||
* @return {@literal true} if the given {@link Exception} is a {@link MongoException} holding one of the transient
|
||||
* exception error labels.
|
||||
* @see MongoException#hasErrorLabel(String)
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isTransientFailure(Exception e) {
|
||||
|
||||
if (!(e instanceof MongoException)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MongoException mongoException = (MongoException) e;
|
||||
|
||||
return mongoException.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)
|
||||
|| mongoException.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContextEvent;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -155,7 +154,7 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
|
||||
IndexOperations indexOperations = indexOperationsProvider.indexOps(indexDefinition.getCollection());
|
||||
indexOperations.ensureIndex(indexDefinition);
|
||||
|
||||
} catch (UncategorizedMongoDbException ex) {
|
||||
} catch (DataIntegrityViolationException ex) {
|
||||
|
||||
if (ex.getCause() instanceof MongoException
|
||||
&& MongoDbErrorCodes.isDataIntegrityViolationCode(((MongoException) ex.getCause()).getCode())) {
|
||||
|
||||
@@ -23,10 +23,10 @@ import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.Index;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
|
||||
@@ -117,7 +117,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
|
||||
MongoEntityMetadata<?> metadata = query.getQueryMethod().getEntityInformation();
|
||||
try {
|
||||
indexOperationsProvider.indexOps(metadata.getCollectionName(), metadata.getJavaType()).ensureIndex(index);
|
||||
} catch (UncategorizedMongoDbException e) {
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
|
||||
if (e.getCause() instanceof MongoException) {
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.HashMap;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* {@link MongoDbErrorCodes} holds MongoDB specific error codes outlined in {@literal mongo/base/error_codes.err}.
|
||||
*
|
||||
@@ -34,7 +36,6 @@ public final class MongoDbErrorCodes {
|
||||
static HashMap<Integer, String> invalidDataAccessApiUsageExeption;
|
||||
static HashMap<Integer, String> permissionDeniedCodes;
|
||||
static HashMap<Integer, String> clientSessionCodes;
|
||||
static HashMap<Integer, String> transactionCodes;
|
||||
|
||||
static HashMap<Integer, String> errorCodes;
|
||||
|
||||
@@ -96,6 +97,7 @@ public final class MongoDbErrorCodes {
|
||||
invalidDataAccessApiUsageExeption.put(72, "InvalidOptions");
|
||||
invalidDataAccessApiUsageExeption.put(115, "CommandNotSupported");
|
||||
invalidDataAccessApiUsageExeption.put(116, "DocTooLargeForCapped");
|
||||
invalidDataAccessApiUsageExeption.put(10003, "CannotGrowDocumentInCappedNamespace");
|
||||
invalidDataAccessApiUsageExeption.put(130, "SymbolNotFound");
|
||||
invalidDataAccessApiUsageExeption.put(17280, "KeyTooLong");
|
||||
invalidDataAccessApiUsageExeption.put(13334, "ShardKeyTooBig");
|
||||
@@ -113,18 +115,18 @@ public final class MongoDbErrorCodes {
|
||||
clientSessionCodes = new HashMap<>(4, 1f);
|
||||
clientSessionCodes.put(206, "NoSuchSession");
|
||||
clientSessionCodes.put(213, "DuplicateSession");
|
||||
clientSessionCodes.put(217, "IncompleteTransactionHistory");
|
||||
clientSessionCodes.put(225, "TransactionTooOld");
|
||||
clientSessionCodes.put(228, "SessionTransferIncomplete");
|
||||
clientSessionCodes.put(244, "TransactionAborted");
|
||||
clientSessionCodes.put(251, "NoSuchTransaction");
|
||||
clientSessionCodes.put(256, "TransactionCommitted");
|
||||
clientSessionCodes.put(257, "TransactionToLarge");
|
||||
clientSessionCodes.put(261, "TooManyLogicalSessions");
|
||||
clientSessionCodes.put(263, "OperationNotSupportedInTransaction");
|
||||
clientSessionCodes.put(264, "TooManyLogicalSessions");
|
||||
|
||||
transactionCodes = new HashMap<>(8, 1f);
|
||||
transactionCodes.put(217, "IncompleteTransactionHistory");
|
||||
transactionCodes.put(225, "TransactionTooOld");
|
||||
transactionCodes.put(244, "TransactionAborted");
|
||||
transactionCodes.put(251, "NoSuchTransaction");
|
||||
transactionCodes.put(256, "TransactionCommitted");
|
||||
transactionCodes.put(257, "TransactionToLarge");
|
||||
transactionCodes.put(263, "OperationNotSupportedInTransaction");
|
||||
transactionCodes.put(267, "PreparedTransactionInProgress");
|
||||
clientSessionCodes.put(267, "PreparedTransactionInProgress");
|
||||
clientSessionCodes.put(290, "TransactionExceededLifetimeLimitSeconds");
|
||||
|
||||
errorCodes = new HashMap<>();
|
||||
errorCodes.putAll(dataAccessResourceFailureCodes);
|
||||
@@ -139,22 +141,100 @@ public final class MongoDbErrorCodes {
|
||||
return errorCode == null ? false : dataIntegrityViolationCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataIntegrityViolationError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDataIntegrityViolationCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDataAccessResourceFailureCode(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? false : dataAccessResourceFailureCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataAccessResourceError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDataAccessResourceFailureCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDuplicateKeyCode(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? false : duplicateKeyCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDuplicateKeyError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDuplicateKeyCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataDuplicateKeyError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDuplicateKeyCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPermissionDeniedCode(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? false : permissionDeniedCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isPermissionDeniedError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isPermissionDeniedCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isInvalidDataAccessApiUsageCode(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? false : invalidDataAccessApiUsageExeption.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isInvalidDataAccessApiUsageError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isInvalidDataAccessApiUsageCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getErrorDescription(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? null : errorCodes.get(errorCode);
|
||||
}
|
||||
@@ -171,13 +251,15 @@ public final class MongoDbErrorCodes {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given error code matches a know transaction related error.
|
||||
*
|
||||
* @param errorCode the error code to check.
|
||||
* @return {@literal true} if error matches.
|
||||
* @since 2.1
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isTransactionFailureCode(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? false : transactionCodes.containsKey(errorCode);
|
||||
public static boolean isClientSessionFailure(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isClientSessionFailureCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,16 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import org.bson.BsonDocument;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.MongoTransactionException;
|
||||
import org.springframework.data.mongodb.TransientMongoDbException;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -38,7 +39,9 @@ import com.mongodb.MongoInternalException;
|
||||
import com.mongodb.MongoSocketException;
|
||||
import com.mongodb.MongoSocketReadTimeoutException;
|
||||
import com.mongodb.MongoSocketWriteException;
|
||||
import com.mongodb.MongoWriteException;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteError;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MongoExceptionTranslator}.
|
||||
@@ -79,15 +82,13 @@ class MongoExceptionTranslatorUnitTests {
|
||||
void translateSocketExceptionSubclasses() {
|
||||
|
||||
expectExceptionWithCauseMessage(
|
||||
translator.translateExceptionIfPossible(
|
||||
new MongoSocketWriteException("intermediate message", new ServerAddress(), new Exception(EXCEPTION_MESSAGE))
|
||||
),
|
||||
translator.translateExceptionIfPossible(new MongoSocketWriteException("intermediate message",
|
||||
new ServerAddress(), new Exception(EXCEPTION_MESSAGE))),
|
||||
DataAccessResourceFailureException.class, EXCEPTION_MESSAGE);
|
||||
|
||||
expectExceptionWithCauseMessage(
|
||||
translator.translateExceptionIfPossible(
|
||||
new MongoSocketReadTimeoutException("intermediate message", new ServerAddress(), new Exception(EXCEPTION_MESSAGE))
|
||||
),
|
||||
translator.translateExceptionIfPossible(new MongoSocketReadTimeoutException("intermediate message",
|
||||
new ServerAddress(), new Exception(EXCEPTION_MESSAGE))),
|
||||
DataAccessResourceFailureException.class, EXCEPTION_MESSAGE);
|
||||
|
||||
}
|
||||
@@ -171,6 +172,38 @@ class MongoExceptionTranslatorUnitTests {
|
||||
checkTranslatedMongoException(MongoTransactionException.class, 267);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void translateTransientTransactionExceptions() {
|
||||
|
||||
MongoException source = new MongoException(267, "PreparedTransactionInProgress");
|
||||
source.addLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL);
|
||||
|
||||
expectExceptionWithCauseMessage(translator.translateExceptionIfPossible(source), TransientMongoDbException.class,
|
||||
"PreparedTransactionInProgress");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void translateMongoExceptionWithTransientLabelToTransientMongoDbException() {
|
||||
|
||||
MongoException exception = new MongoException(0, "");
|
||||
exception.addLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
|
||||
|
||||
expectExceptionWithCauseMessage(translatedException, TransientMongoDbException.class);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void wrapsTranslatedExceptionsWhenTransientLabelPresent() {
|
||||
|
||||
MongoException exception = new MongoWriteException(new WriteError(112, "WriteConflict", new BsonDocument()), null);
|
||||
exception.addLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
|
||||
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
|
||||
|
||||
assertThat(translatedException).isInstanceOf(TransientMongoDbException.class);
|
||||
assertThat(translatedException.getCause()).isInstanceOf(DataIntegrityViolationException.class);
|
||||
}
|
||||
|
||||
private void checkTranslatedMongoException(Class<? extends Exception> clazz, int code) {
|
||||
|
||||
DataAccessException translated = translator.translateExceptionIfPossible(new MongoException(code, ""));
|
||||
|
||||
Reference in New Issue
Block a user