diff --git a/pom.xml b/pom.xml index 2d68144a47..0ce6f4e44b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-jdbc - 1.0.0.BUILD-SNAPSHOT + 1.0.0.DATAJDBC-150-SNAPSHOT Spring Data JDBC Spring Data module for JDBC repositories. diff --git a/src/main/java/org/springframework/data/jdbc/core/conversion/DbAction.java b/src/main/java/org/springframework/data/jdbc/core/conversion/DbAction.java index e5f2fee59d..20d74a17c2 100644 --- a/src/main/java/org/springframework/data/jdbc/core/conversion/DbAction.java +++ b/src/main/java/org/springframework/data/jdbc/core/conversion/DbAction.java @@ -86,7 +86,26 @@ public static DeleteAll deleteAll(Class type, JdbcPropertyPath propert return new DeleteAll<>(type, propertyPath, dependingOn); } - abstract void executeWith(Interpreter interpreter); + /** + * Executing this DbAction with the given {@link Interpreter}. + * + * @param interpreter the {@link Interpreter} responsible for actually executing the {@link DbAction}. + */ + void executeWith(Interpreter interpreter) { + + try { + doExecuteWith(interpreter); + } catch (Exception e) { + throw new DbActionExecutionException(this, e); + } + } + + /** + * Executing this DbAction with the given {@link Interpreter} without any exception handling. + * + * @param interpreter the {@link Interpreter} responsible for actually executing the {@link DbAction}. + */ + protected abstract void doExecuteWith(Interpreter interpreter); /** * {@link InsertOrUpdate} must reference an entity. @@ -113,7 +132,7 @@ private Insert(T entity, JdbcPropertyPath propertyPath, DbAction dependingOn) { } @Override - void executeWith(Interpreter interpreter) { + protected void doExecuteWith(Interpreter interpreter) { interpreter.interpret(this); } } @@ -130,7 +149,7 @@ private Update(T entity, JdbcPropertyPath propertyPath, DbAction dependingOn) { } @Override - void executeWith(Interpreter interpreter) { + protected void doExecuteWith(Interpreter interpreter) { interpreter.interpret(this); } } @@ -159,7 +178,7 @@ private Delete(Object rootId, Class type, T entity, JdbcPropertyPath property } @Override - void executeWith(Interpreter interpreter) { + protected void doExecuteWith(Interpreter interpreter) { interpreter.interpret(this); } } @@ -176,7 +195,7 @@ private DeleteAll(Class entityType, JdbcPropertyPath propertyPath, DbAction d } @Override - void executeWith(Interpreter interpreter) { + protected void doExecuteWith(Interpreter interpreter) { interpreter.interpret(this); } } diff --git a/src/main/java/org/springframework/data/jdbc/core/conversion/DbActionExecutionException.java b/src/main/java/org/springframework/data/jdbc/core/conversion/DbActionExecutionException.java new file mode 100644 index 0000000000..1a7966a7f0 --- /dev/null +++ b/src/main/java/org/springframework/data/jdbc/core/conversion/DbActionExecutionException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 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.jdbc.core.conversion; + +/** + * Exception thrown when during the execution of a {@link DbAction} an exception gets thrown. Provides additional + * context information about the action and the entity. + * + * @author Jens Schauder + */ +public class DbActionExecutionException extends RuntimeException { + public DbActionExecutionException(DbAction action, Throwable cause) { + super( // + String.format("Failed to execute %s for instance %s of type %s with path %s", // + action.getClass().getSimpleName(), // + action.getEntity(), // + action.getEntityType(), // + action.getPropertyPath().toDotPath() // + ), // + cause); + } +} diff --git a/src/test/java/org/springframework/data/jdbc/core/conversion/DbActionUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/conversion/DbActionUnitTests.java new file mode 100644 index 0000000000..1ad5f2e418 --- /dev/null +++ b/src/test/java/org/springframework/data/jdbc/core/conversion/DbActionUnitTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 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.jdbc.core.conversion; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +/** + * Unit tests for {@link DbAction}s + * + * @author Jens Schauder + */ +public class DbActionUnitTests { + + @Test // DATAJDBC-150 + public void exceptionFromActionContainsUsefulInformationWhenInterpreterFails() { + + DummyEntity entity = new DummyEntity(); + DbAction.Insert insert = DbAction.insert(entity, JdbcPropertyPath.from("someName", DummyEntity.class), + null); + + Interpreter failingInterpreter = mock(Interpreter.class); + doThrow(new RuntimeException()).when(failingInterpreter).interpret(any(DbAction.Insert.class)); + + assertThatExceptionOfType(DbActionExecutionException.class) // + .isThrownBy(() -> insert.executeWith(failingInterpreter)) // + .withMessageContaining("Insert") // + .withMessageContaining(entity.toString()); + + } + + static class DummyEntity { + String someName; + } +}