diff --git a/common-api/build.gradle b/common-api/build.gradle index b8e853f..7f977d4 100644 --- a/common-api/build.gradle +++ b/common-api/build.gradle @@ -1,11 +1,15 @@ plugins { id "io.freefair.lombok" version "6.5.0.3" - id 'java' + id 'java-library' } group = 'bitxon.common' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} repositories { mavenCentral() 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/common-wiremock/build.gradle b/common-wiremock/build.gradle index 67b819b..75c1b40 100644 --- a/common-wiremock/build.gradle +++ b/common-wiremock/build.gradle @@ -1,7 +1,11 @@ plugins { - id 'java' + id 'java-library' } group = 'bitxon.common' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} diff --git a/dropwizard-app/build.gradle b/dropwizard-app/build.gradle index 087a396..f8f5ed2 100644 --- a/dropwizard-app/build.gradle +++ b/dropwizard-app/build.gradle @@ -6,7 +6,11 @@ plugins { group = 'bitxon.dropwizard' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} repositories { mavenCentral() 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/build.gradle b/micronaut-app/build.gradle index 61d2412..d4c09dc 100644 --- a/micronaut-app/build.gradle +++ b/micronaut-app/build.gradle @@ -6,8 +6,11 @@ plugins { group = 'bitxon.micronaut' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' -targetCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} repositories { mavenCentral() 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/build.gradle b/quarkus-app/build.gradle index 4c8f62c..0888cdb 100644 --- a/quarkus-app/build.gradle +++ b/quarkus-app/build.gradle @@ -8,7 +8,11 @@ ext.set("quarkus.package.type", "uber-jar") group = 'bitxon.quarkus' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} repositories { mavenCentral() 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/build.gradle b/spring-app/build.gradle index 942cbb7..29dc34e 100644 --- a/spring-app/build.gradle +++ b/spring-app/build.gradle @@ -6,7 +6,11 @@ plugins { group = 'bitxon.spring' version = '1.0-SNAPSHOT' -sourceCompatibility = '17' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} repositories { mavenCentral() 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()