Remove DbActionExecutionException.
We now raise the exceptions from `NamedParameterJdbcTemplate` directly. If you used to extract the `cause` of a `DbActionExecutionException` you should now catch that Exception directly. Original pull request #1956 Closes #831 Signed-off-by: mipo256 <mikhailpolivakha@gmail.com>
This commit is contained in:
@@ -15,22 +15,21 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.DbActionExecutionException;
|
||||
import org.springframework.data.relational.core.conversion.MutableAggregateChange;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes an {@link MutableAggregateChange}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Chirag Tailor
|
||||
* @author Mikhail Polivakha
|
||||
* @since 2.0
|
||||
*/
|
||||
class AggregateChangeExecutor {
|
||||
@@ -79,43 +78,34 @@ class AggregateChangeExecutor {
|
||||
}
|
||||
|
||||
private void execute(DbAction<?> action, JdbcAggregateChangeExecutionContext executionContext) {
|
||||
|
||||
try {
|
||||
if (action instanceof DbAction.InsertRoot<?> insertRoot) {
|
||||
executionContext.executeInsertRoot(insertRoot);
|
||||
} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) {
|
||||
executionContext.executeBatchInsertRoot(batchInsertRoot);
|
||||
} else if (action instanceof DbAction.Insert<?> insert) {
|
||||
executionContext.executeInsert(insert);
|
||||
} else if (action instanceof DbAction.BatchInsert<?> batchInsert) {
|
||||
executionContext.executeBatchInsert(batchInsert);
|
||||
} else if (action instanceof DbAction.UpdateRoot<?> updateRoot) {
|
||||
executionContext.executeUpdateRoot(updateRoot);
|
||||
} else if (action instanceof DbAction.Delete<?> delete) {
|
||||
executionContext.executeDelete(delete);
|
||||
} else if (action instanceof DbAction.BatchDelete<?> batchDelete) {
|
||||
executionContext.executeBatchDelete(batchDelete);
|
||||
} else if (action instanceof DbAction.DeleteAll<?> deleteAll) {
|
||||
executionContext.executeDeleteAll(deleteAll);
|
||||
} else if (action instanceof DbAction.DeleteRoot<?> deleteRoot) {
|
||||
executionContext.executeDeleteRoot(deleteRoot);
|
||||
} else if (action instanceof DbAction.BatchDeleteRoot<?> batchDeleteRoot) {
|
||||
executionContext.executeBatchDeleteRoot(batchDeleteRoot);
|
||||
} else if (action instanceof DbAction.DeleteAllRoot<?> deleteAllRoot) {
|
||||
executionContext.executeDeleteAllRoot(deleteAllRoot);
|
||||
} else if (action instanceof DbAction.AcquireLockRoot<?> acquireLockRoot) {
|
||||
executionContext.executeAcquireLock(acquireLockRoot);
|
||||
} else if (action instanceof DbAction.AcquireLockAllRoot<?> acquireLockAllRoot) {
|
||||
executionContext.executeAcquireLockAllRoot(acquireLockAllRoot);
|
||||
} else {
|
||||
throw new RuntimeException("unexpected action");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
if (e instanceof OptimisticLockingFailureException) {
|
||||
throw e;
|
||||
}
|
||||
throw new DbActionExecutionException(action, e);
|
||||
if (action instanceof DbAction.InsertRoot<?> insertRoot) {
|
||||
executionContext.executeInsertRoot(insertRoot);
|
||||
} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) {
|
||||
executionContext.executeBatchInsertRoot(batchInsertRoot);
|
||||
} else if (action instanceof DbAction.Insert<?> insert) {
|
||||
executionContext.executeInsert(insert);
|
||||
} else if (action instanceof DbAction.BatchInsert<?> batchInsert) {
|
||||
executionContext.executeBatchInsert(batchInsert);
|
||||
} else if (action instanceof DbAction.UpdateRoot<?> updateRoot) {
|
||||
executionContext.executeUpdateRoot(updateRoot);
|
||||
} else if (action instanceof DbAction.Delete<?> delete) {
|
||||
executionContext.executeDelete(delete);
|
||||
} else if (action instanceof DbAction.BatchDelete<?> batchDelete) {
|
||||
executionContext.executeBatchDelete(batchDelete);
|
||||
} else if (action instanceof DbAction.DeleteAll<?> deleteAll) {
|
||||
executionContext.executeDeleteAll(deleteAll);
|
||||
} else if (action instanceof DbAction.DeleteRoot<?> deleteRoot) {
|
||||
executionContext.executeDeleteRoot(deleteRoot);
|
||||
} else if (action instanceof DbAction.BatchDeleteRoot<?> batchDeleteRoot) {
|
||||
executionContext.executeBatchDeleteRoot(batchDeleteRoot);
|
||||
} else if (action instanceof DbAction.DeleteAllRoot<?> deleteAllRoot) {
|
||||
executionContext.executeDeleteAllRoot(deleteAllRoot);
|
||||
} else if (action instanceof DbAction.AcquireLockRoot<?> acquireLockRoot) {
|
||||
executionContext.executeAcquireLock(acquireLockRoot);
|
||||
} else if (action instanceof DbAction.AcquireLockAllRoot<?> acquireLockAllRoot) {
|
||||
executionContext.executeAcquireLockAllRoot(acquireLockAllRoot);
|
||||
} else {
|
||||
throw new RuntimeException("unexpected action");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,9 +563,8 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests {
|
||||
LegoSet entity = new LegoSet();
|
||||
entity.id = 100L; // does not exist in the database
|
||||
|
||||
assertThatExceptionOfType(DbActionExecutionException.class) //
|
||||
.isThrownBy(() -> template.save(entity)) //
|
||||
.withCauseInstanceOf(IncorrectUpdateSemanticsDataAccessException.class);
|
||||
assertThatExceptionOfType(IncorrectUpdateSemanticsDataAccessException.class) //
|
||||
.isThrownBy(() -> template.save(entity));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -1165,7 +1164,7 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests {
|
||||
aggregate.setVersion(null);
|
||||
aggregate.setId(23L);
|
||||
|
||||
assertThatThrownBy(() -> template.save(aggregate)).isInstanceOf(DbActionExecutionException.class);
|
||||
assertThatThrownBy(() -> template.save(aggregate)).isInstanceOf(IncorrectUpdateSemanticsDataAccessException.class);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-462
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
*
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Jens Schauder
|
||||
* @author Mikhail Polivakha
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
public class JdbcRepositoryConcurrencyIntegrationTests {
|
||||
@@ -159,7 +160,7 @@ public class JdbcRepositoryConcurrencyIntegrationTests {
|
||||
} catch (Exception ex) {
|
||||
// When the delete execution is complete, the Update execution throws an
|
||||
// IncorrectUpdateSemanticsDataAccessException.
|
||||
if (ex.getCause() instanceof IncorrectUpdateSemanticsDataAccessException) {
|
||||
if (ex instanceof IncorrectUpdateSemanticsDataAccessException) {
|
||||
return null;
|
||||
}
|
||||
throw ex;
|
||||
@@ -193,7 +194,7 @@ public class JdbcRepositoryConcurrencyIntegrationTests {
|
||||
} catch (Exception ex) {
|
||||
// When the delete execution is complete, the Update execution throws an
|
||||
// IncorrectUpdateSemanticsDataAccessException.
|
||||
if (ex.getCause() instanceof IncorrectUpdateSemanticsDataAccessException) {
|
||||
if (ex instanceof IncorrectUpdateSemanticsDataAccessException) {
|
||||
return null;
|
||||
}
|
||||
throw ex;
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.SoftAssertions.assertSoftly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.ResultSet;
|
||||
@@ -37,6 +39,7 @@ import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -49,9 +52,21 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.data.domain.Limit;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.domain.ScrollPosition;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Window;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.jdbc.repository.query.Modifying;
|
||||
import org.springframework.data.jdbc.repository.query.Query;
|
||||
@@ -64,8 +79,8 @@ import org.springframework.data.jdbc.testing.TestConfiguration;
|
||||
import org.springframework.data.jdbc.testing.TestDatabaseFeatures;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
import org.springframework.data.relational.core.mapping.Sequence;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
import org.springframework.data.relational.core.mapping.event.AbstractRelationalEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
@@ -104,6 +119,8 @@ public class JdbcRepositoryIntegrationTests {
|
||||
|
||||
@Autowired NamedParameterJdbcTemplate template;
|
||||
@Autowired DummyEntityRepository repository;
|
||||
|
||||
@Autowired ProvidedIdEntityRepository providedIdEntityRepository;
|
||||
@Autowired MyEventListener eventListener;
|
||||
@Autowired RootRepository rootRepository;
|
||||
@Autowired WithDelimitedColumnRepository withDelimitedColumnRepository;
|
||||
@@ -208,6 +225,18 @@ public class JdbcRepositoryIntegrationTests {
|
||||
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-611
|
||||
public void testDuplicateKeyExceptionIsThrownInCaseOfUniqueKeyViolation() {
|
||||
|
||||
// given.
|
||||
ProvidedIdEntity first = ProvidedIdEntity.newInstance(1L, "name");
|
||||
ProvidedIdEntity second = ProvidedIdEntity.newInstance(1L, "other");
|
||||
|
||||
// when/then
|
||||
Assertions.assertThatCode(() -> providedIdEntityRepository.save(first)).doesNotThrowAnyException();
|
||||
Assertions.assertThatThrownBy(() -> providedIdEntityRepository.save(second)).isInstanceOf(DuplicateKeyException.class);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-97
|
||||
public void countsEntities() {
|
||||
|
||||
@@ -1436,6 +1465,10 @@ public class JdbcRepositoryIntegrationTests {
|
||||
String getName();
|
||||
}
|
||||
|
||||
interface ProvidedIdEntityRepository extends CrudRepository<ProvidedIdEntity, Long> {
|
||||
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, QueryByExampleExecutor<DummyEntity> {
|
||||
|
||||
@Lock(LockMode.PESSIMISTIC_WRITE)
|
||||
@@ -1543,6 +1576,11 @@ public class JdbcRepositoryIntegrationTests {
|
||||
return factory.getRepository(DummyEntityRepository.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
ProvidedIdEntityRepository providedIdEntityRepository() {
|
||||
return factory.getRepository(ProvidedIdEntityRepository.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RootRepository rootRepository() {
|
||||
return factory.getRepository(RootRepository.class);
|
||||
@@ -1886,6 +1924,37 @@ public class JdbcRepositoryIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
static class ProvidedIdEntity implements Persistable<Long> {
|
||||
|
||||
@Id
|
||||
private final Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Transient
|
||||
private boolean isNew;
|
||||
|
||||
private ProvidedIdEntity(Long id, String name, boolean isNew) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.isNew = isNew;
|
||||
}
|
||||
|
||||
private static ProvidedIdEntity newInstance(Long id, String name) {
|
||||
return new ProvidedIdEntity(id, name, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return isNew;
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyEntity {
|
||||
|
||||
String name;
|
||||
|
||||
@@ -5,6 +5,7 @@ DROP TABLE LEAF;
|
||||
DROP TABLE WITH_DELIMITED_COLUMN;
|
||||
DROP TABLE ENTITY_WITH_SEQUENCE;
|
||||
DROP SEQUENCE ENTITY_SEQUENCE;
|
||||
DROP TABLE PROVIDED_ID_ENTITY;
|
||||
|
||||
CREATE TABLE dummy_entity
|
||||
(
|
||||
@@ -55,4 +56,8 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -47,4 +47,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -47,4 +47,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -47,4 +47,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE `ENTITY_SEQUENCE` START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE SEQUENCE `ENTITY_SEQUENCE` START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ DROP TABLE IF EXISTS LEAF;
|
||||
DROP TABLE IF EXISTS WITH_DELIMITED_COLUMN;
|
||||
DROP TABLE IF EXISTS ENTITY_WITH_SEQUENCE;
|
||||
DROP SEQUENCE IF EXISTS ENTITY_SEQUENCE;
|
||||
DROP TABLE IF EXISTS PROVIDED_ID_ENTITY;
|
||||
|
||||
CREATE TABLE dummy_entity
|
||||
(
|
||||
@@ -55,4 +56,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -42,4 +42,10 @@ CREATE TABLE WITH_DELIMITED_COLUMN
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
`ORG.XTUNIT.IDENTIFIER` VARCHAR(100),
|
||||
STYPE VARCHAR(100)
|
||||
);
|
||||
);
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ DROP TABLE LEAF CASCADE CONSTRAINTS PURGE;
|
||||
DROP TABLE WITH_DELIMITED_COLUMN CASCADE CONSTRAINTS PURGE;
|
||||
DROP TABLE ENTITY_WITH_SEQUENCE CASCADE CONSTRAINTS PURGE;
|
||||
DROP SEQUENCE ENTITY_SEQUENCE;
|
||||
DROP TABLE PROVIDED_ID_ENTITY CASCADE CONSTRAINTS PURGE;
|
||||
|
||||
CREATE TABLE DUMMY_ENTITY
|
||||
(
|
||||
@@ -55,4 +56,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1;
|
||||
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ DROP TABLE LEAF;
|
||||
DROP TABLE WITH_DELIMITED_COLUMN;
|
||||
DROP TABLE ENTITY_WITH_SEQUENCE;
|
||||
DROP SEQUENCE ENTITY_SEQUENCE;
|
||||
DROP TABLE PROVIDED_ID_ENTITY;
|
||||
|
||||
CREATE TABLE dummy_entity
|
||||
(
|
||||
@@ -55,4 +56,10 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE "ENTITY_SEQUENCE" START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
CREATE SEQUENCE "ENTITY_SEQUENCE" START WITH 1 INCREMENT BY 1 NO MAXVALUE;
|
||||
|
||||
CREATE TABLE PROVIDED_ID_ENTITY
|
||||
(
|
||||
ID BIGINT PRIMARY KEY,
|
||||
NAME VARCHAR(30)
|
||||
);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2025 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.relational.core.conversion;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit test for {@link DbActionExecutionException}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class DbActionExecutionExceptionUnitTests {
|
||||
|
||||
@Test // DATAJDBC-162
|
||||
public void constructorWorksWithNullPropertyPath() {
|
||||
|
||||
DbAction<?> action = mock(DbAction.class);
|
||||
new DbActionExecutionException(action, null);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user