diff --git a/common-api/src/main/java/bitxon/common/exception/DirtyTrickException.java b/common-api/src/main/java/bitxon/common/exception/DirtyTrickException.java new file mode 100644 index 0000000..d21b1c4 --- /dev/null +++ b/common-api/src/main/java/bitxon/common/exception/DirtyTrickException.java @@ -0,0 +1,8 @@ +package bitxon.common.exception; + +public class DirtyTrickException extends RuntimeException { + + public DirtyTrickException(String message) { + super("Dirty Trick: " + message); + } +} diff --git a/dropwizard-app/src/main/java/bitxon/dropwizard/DropwizardApplication.java b/dropwizard-app/src/main/java/bitxon/dropwizard/DropwizardApplication.java index 5ebde37..c345b51 100644 --- a/dropwizard-app/src/main/java/bitxon/dropwizard/DropwizardApplication.java +++ b/dropwizard-app/src/main/java/bitxon/dropwizard/DropwizardApplication.java @@ -5,6 +5,7 @@ import bitxon.dropwizard.db.AccountDao; import bitxon.dropwizard.db.AccountDaoHibernateImpl; import bitxon.dropwizard.db.model.Account; +import bitxon.dropwizard.errorhandler.DirtyTrickExceptionHandler; import bitxon.dropwizard.errorhandler.JerseyViolationExceptionHandler; import bitxon.dropwizard.errorhandler.ResourceNotFoundExceptionHandler; import bitxon.dropwizard.mapper.AccountMapper; @@ -63,6 +64,7 @@ protected void configure() { environment.jersey().register(AccountResource.class); + environment.jersey().register(DirtyTrickExceptionHandler.class); environment.jersey().register(JerseyViolationExceptionHandler.class); environment.jersey().register(ResourceNotFoundExceptionHandler.class); } diff --git a/dropwizard-app/src/main/java/bitxon/dropwizard/errorhandler/DirtyTrickExceptionHandler.java b/dropwizard-app/src/main/java/bitxon/dropwizard/errorhandler/DirtyTrickExceptionHandler.java new file mode 100644 index 0000000..269d4bc --- /dev/null +++ b/dropwizard-app/src/main/java/bitxon/dropwizard/errorhandler/DirtyTrickExceptionHandler.java @@ -0,0 +1,20 @@ +package bitxon.dropwizard.errorhandler; + +import bitxon.common.api.model.error.ErrorResponse; +import bitxon.common.exception.DirtyTrickException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +import java.util.List; + +@Provider +public class DirtyTrickExceptionHandler implements ExceptionMapper { + + @Override + public Response toResponse(DirtyTrickException ex) { + return Response + .status(500) + .entity(new ErrorResponse(List.of(ex.getMessage()))).build(); + } +} diff --git a/dropwizard-app/src/main/java/bitxon/dropwizard/resource/AccountResource.java b/dropwizard-app/src/main/java/bitxon/dropwizard/resource/AccountResource.java index 8c4b105..db2a4e6 100644 --- a/dropwizard-app/src/main/java/bitxon/dropwizard/resource/AccountResource.java +++ b/dropwizard-app/src/main/java/bitxon/dropwizard/resource/AccountResource.java @@ -5,6 +5,7 @@ import bitxon.common.api.model.Account; import bitxon.common.api.model.MoneyTransfer; +import bitxon.common.exception.DirtyTrickException; import bitxon.common.exception.ResourceNotFoundException; import bitxon.dropwizard.client.exchange.ExchangeClient; import bitxon.dropwizard.db.AccountDao; @@ -82,7 +83,7 @@ public void transfer(@NotNull @Valid MoneyTransfer transfer, dao.save(sender); if (FAIL_TRANSFER.equals(dirtyTrick)) { - throw new RuntimeException("Error during money transfer"); + throw new DirtyTrickException("Error during money transfer"); } recipient.setMoneyAmount(recipient.getMoneyAmount() + (int)(transfer.moneyAmount() * exchangeRateValue)); diff --git a/dropwizard-app/src/test/java/bitxon/dropwizard/test/MoneyTransferDropwizardTest.java b/dropwizard-app/src/test/java/bitxon/dropwizard/test/MoneyTransferDropwizardTest.java index 2a471d2..861d6c9 100644 --- a/dropwizard-app/src/test/java/bitxon/dropwizard/test/MoneyTransferDropwizardTest.java +++ b/dropwizard-app/src/test/java/bitxon/dropwizard/test/MoneyTransferDropwizardTest.java @@ -71,7 +71,8 @@ void transferWithServerProblemDuringTransfer() { .when() .post("/accounts/transfers") .then() - .statusCode(500); + .statusCode(500) + .body("errors", hasItem("Dirty Trick: Error during money transfer")); //@formatter:on get("/accounts/" + senderId).then() diff --git a/micronaut-app/src/main/java/bitxon/micronaut/controller/AccountController.java b/micronaut-app/src/main/java/bitxon/micronaut/controller/AccountController.java index 7719b61..9cdd418 100644 --- a/micronaut-app/src/main/java/bitxon/micronaut/controller/AccountController.java +++ b/micronaut-app/src/main/java/bitxon/micronaut/controller/AccountController.java @@ -5,6 +5,7 @@ import bitxon.common.api.model.Account; import bitxon.common.api.model.MoneyTransfer; +import bitxon.common.exception.DirtyTrickException; import bitxon.common.exception.ResourceNotFoundException; import bitxon.micronaut.client.exchange.ExchangeClient; import bitxon.micronaut.db.AccountDao; @@ -82,7 +83,7 @@ public void transfer(@Body @Valid MoneyTransfer transfer, dao.save(sender); if (FAIL_TRANSFER.equals(dirtyTrick)) { - throw new RuntimeException("Error during money transfer"); + throw new DirtyTrickException("Error during money transfer"); } recipient.setMoneyAmount(recipient.getMoneyAmount() + (int) (transfer.moneyAmount() * exchangeRateValue)); diff --git a/micronaut-app/src/main/java/bitxon/micronaut/errorhandler/DirtyTrickExceptionHandler.java b/micronaut-app/src/main/java/bitxon/micronaut/errorhandler/DirtyTrickExceptionHandler.java new file mode 100644 index 0000000..a20368c --- /dev/null +++ b/micronaut-app/src/main/java/bitxon/micronaut/errorhandler/DirtyTrickExceptionHandler.java @@ -0,0 +1,25 @@ +package bitxon.micronaut.errorhandler; + +import bitxon.common.api.model.error.ErrorResponse; +import bitxon.common.exception.DirtyTrickException; +import io.micronaut.context.annotation.Requires; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.annotation.Produces; +import io.micronaut.http.server.exceptions.ExceptionHandler; +import jakarta.inject.Singleton; + +import java.util.List; + +@Produces +@Singleton +@Requires(classes = {DirtyTrickException.class, ExceptionHandler.class}) +public class DirtyTrickExceptionHandler implements ExceptionHandler { + @Override + public HttpResponse handle(HttpRequest request, DirtyTrickException ex) { + return HttpResponse + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ErrorResponse(List.of(ex.getMessage()))); + } +} diff --git a/micronaut-app/src/test/java/bitxon/micronaut/test/MoneyTransferMicronautTest.java b/micronaut-app/src/test/java/bitxon/micronaut/test/MoneyTransferMicronautTest.java index 477373f..f3f74c9 100644 --- a/micronaut-app/src/test/java/bitxon/micronaut/test/MoneyTransferMicronautTest.java +++ b/micronaut-app/src/test/java/bitxon/micronaut/test/MoneyTransferMicronautTest.java @@ -72,7 +72,8 @@ void transferWithServerProblemDuringTransfer() { .when() .post("/accounts/transfers") .then() - .statusCode(500); + .statusCode(500) + .body("errors", hasItem("Dirty Trick: Error during money transfer")); //@formatter:on RestAssured.get("/accounts/" + senderId).then() diff --git a/quarkus-app/src/main/java/bitxon/quarkus/errorhandler/DirtyTrickExceptionHandler.java b/quarkus-app/src/main/java/bitxon/quarkus/errorhandler/DirtyTrickExceptionHandler.java new file mode 100644 index 0000000..0acf7cb --- /dev/null +++ b/quarkus-app/src/main/java/bitxon/quarkus/errorhandler/DirtyTrickExceptionHandler.java @@ -0,0 +1,20 @@ +package bitxon.quarkus.errorhandler; + +import bitxon.common.api.model.error.ErrorResponse; +import bitxon.common.exception.DirtyTrickException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +import java.util.List; + +@Provider +public class DirtyTrickExceptionHandler implements ExceptionMapper { + + @Override + public Response toResponse(DirtyTrickException ex) { + return Response + .status(500) + .entity(new ErrorResponse(List.of(ex.getMessage()))).build(); + } +} diff --git a/quarkus-app/src/main/java/bitxon/quarkus/resource/AccountResource.java b/quarkus-app/src/main/java/bitxon/quarkus/resource/AccountResource.java index 8181672..3c66234 100644 --- a/quarkus-app/src/main/java/bitxon/quarkus/resource/AccountResource.java +++ b/quarkus-app/src/main/java/bitxon/quarkus/resource/AccountResource.java @@ -5,6 +5,7 @@ import bitxon.common.api.model.Account; import bitxon.common.api.model.MoneyTransfer; +import bitxon.common.exception.DirtyTrickException; import bitxon.common.exception.ResourceNotFoundException; import bitxon.quarkus.client.exchange.ExchangeClient; import bitxon.quarkus.db.AccountDao; @@ -78,7 +79,7 @@ public void transfer(@Valid MoneyTransfer transfer, dao.save(sender); if (FAIL_TRANSFER.equals(dirtyTrick)) { - throw new RuntimeException("Error during money transfer"); + throw new DirtyTrickException("Error during money transfer"); } recipient.setMoneyAmount(recipient.getMoneyAmount() + (int)(transfer.moneyAmount() * exchangeRateValue)); diff --git a/quarkus-app/src/test/java/bitxon/quarkus/test/MoneyTransferQuarkusTest.java b/quarkus-app/src/test/java/bitxon/quarkus/test/MoneyTransferQuarkusTest.java index 1ae1d3f..01b7cea 100644 --- a/quarkus-app/src/test/java/bitxon/quarkus/test/MoneyTransferQuarkusTest.java +++ b/quarkus-app/src/test/java/bitxon/quarkus/test/MoneyTransferQuarkusTest.java @@ -74,7 +74,8 @@ void transferWithServerProblemDuringTransfer() { .when() .post("/accounts/transfers") .then() - .statusCode(500); + .statusCode(500) + .body("errors", hasItem("Dirty Trick: Error during money transfer")); //@formatter:on get("/accounts/" + senderId).then() diff --git a/spring-app/src/main/java/bitxon/spring/controller/AccountController.java b/spring-app/src/main/java/bitxon/spring/controller/AccountController.java index 0cc67bd..d2b161a 100644 --- a/spring-app/src/main/java/bitxon/spring/controller/AccountController.java +++ b/spring-app/src/main/java/bitxon/spring/controller/AccountController.java @@ -5,6 +5,7 @@ import bitxon.common.api.model.Account; import bitxon.common.api.model.MoneyTransfer; +import bitxon.common.exception.DirtyTrickException; import bitxon.common.exception.ResourceNotFoundException; import bitxon.spring.client.ExchangeClient; import bitxon.spring.db.AccountDao; @@ -80,7 +81,7 @@ public void transfer(@Valid @RequestBody MoneyTransfer transfer, dao.save(sender); if (FAIL_TRANSFER.equals(dirtyTrick)) { - throw new RuntimeException("Error during money transfer"); + throw new DirtyTrickException("Error during money transfer"); } recipient.setMoneyAmount(recipient.getMoneyAmount() + (int) (transfer.moneyAmount() * exchangeRateValue)); diff --git a/spring-app/src/main/java/bitxon/spring/errorhandler/ErrorControllerAdvice.java b/spring-app/src/main/java/bitxon/spring/errorhandler/ErrorControllerAdvice.java index 90a459d..3ccbc23 100644 --- a/spring-app/src/main/java/bitxon/spring/errorhandler/ErrorControllerAdvice.java +++ b/spring-app/src/main/java/bitxon/spring/errorhandler/ErrorControllerAdvice.java @@ -1,6 +1,7 @@ package bitxon.spring.errorhandler; import bitxon.common.api.model.error.ErrorResponse; +import bitxon.common.exception.DirtyTrickException; import bitxon.common.exception.ResourceNotFoundException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @@ -25,6 +26,11 @@ public ResponseEntity handle(Exception ex) { return create(500, "Unknown error, see logs."); } + @ExceptionHandler(DirtyTrickException.class) + public ResponseEntity handle(DirtyTrickException ex) { + return create(500, ex.getMessage()); + } + @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity handle(ResourceNotFoundException ex) { return create(404, ex.getMessage()); diff --git a/spring-app/src/test/java/bitxon/spring/test/MoneyTransferSpringTest.java b/spring-app/src/test/java/bitxon/spring/test/MoneyTransferSpringTest.java index 52b76ce..b34ee6d 100644 --- a/spring-app/src/test/java/bitxon/spring/test/MoneyTransferSpringTest.java +++ b/spring-app/src/test/java/bitxon/spring/test/MoneyTransferSpringTest.java @@ -72,7 +72,8 @@ void transferWithServerProblemDuringTransfer() { .when() .post("/accounts/transfers") .then() - .statusCode(500); + .statusCode(500) + .body("errors", hasItem("Dirty Trick: Error during money transfer")); //@formatter:on get("/accounts/" + senderId).then()