From 5187169c3e624a162440d3f5c7a8d1e76af97d43 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:50:48 -0500 Subject: [PATCH 1/2] add json exception --- .../io/avaje/jex/core/ExceptionManager.java | 3 ++ .../avaje/jex/http/BadRequestException.java | 2 +- .../avaje/jex/http/HttpResponseException.java | 29 ++++++++++++------- .../http/InternalServerErrorException.java | 6 +++- .../io/avaje/jex/http/NotFoundException.java | 4 +++ 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/avaje-jex/src/main/java/io/avaje/jex/core/ExceptionManager.java b/avaje-jex/src/main/java/io/avaje/jex/core/ExceptionManager.java index b734e0df..6d11cdf4 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/core/ExceptionManager.java +++ b/avaje-jex/src/main/java/io/avaje/jex/core/ExceptionManager.java @@ -57,8 +57,11 @@ private void unhandledException(JdkContext ctx, Exception e) { private void defaultHandling(JdkContext ctx, HttpResponseException exception) { ctx.status(exception.getStatus()); + var jsonResponse = exception.jsonResponse(); if (exception.getStatus() == ErrorCode.REDIRECT.status()) { ctx.performRedirect(); + } else if (jsonResponse != null) { + ctx.json(jsonResponse); } else if (useJson(ctx)) { ctx.contentType(APPLICATION_JSON).write(asJsonContent(exception)); } else { diff --git a/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java b/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java index c9cc523a..41548e62 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java +++ b/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java @@ -1,6 +1,6 @@ package io.avaje.jex.http; -/** Thrown when unable to find a route/resource */ +/** Thrown when request is invalid */ public class BadRequestException extends HttpResponseException { public BadRequestException(String message) { diff --git a/avaje-jex/src/main/java/io/avaje/jex/http/HttpResponseException.java b/avaje-jex/src/main/java/io/avaje/jex/http/HttpResponseException.java index 613894f2..cd33965c 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/http/HttpResponseException.java +++ b/avaje-jex/src/main/java/io/avaje/jex/http/HttpResponseException.java @@ -1,32 +1,39 @@ package io.avaje.jex.http; -import java.util.Collections; -import java.util.Map; - /** * Throwing an uncaught {@code HttpResponseException} will interrupt http processing and set the - * status code and response body with the given message + * status code and response body with the given message or json body */ public class HttpResponseException extends RuntimeException { private final int status; - private final Map details; + private final Object jsonResponse; - public HttpResponseException(int status, String message, Map details) { + /** + * @param status the http status to send + * @param message the exception message that will be sent back in the response + */ + public HttpResponseException(int status, String message) { super(message); this.status = status; - this.details = details; + this.jsonResponse = null; } - public HttpResponseException(int status, String message) { - this(status, message, Collections.emptyMap()); + /** + * @param status the http status to send + * @param jsonResponse the response body that will be sent back as json + */ + public HttpResponseException(int status, Object jsonResponse) { + + this.status = status; + this.jsonResponse = jsonResponse; } public int getStatus() { return status; } - public Map getDetails() { - return details; + public Object jsonResponse() { + return jsonResponse; } } diff --git a/avaje-jex/src/main/java/io/avaje/jex/http/InternalServerErrorException.java b/avaje-jex/src/main/java/io/avaje/jex/http/InternalServerErrorException.java index 4ddc7716..c39d2aa0 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/http/InternalServerErrorException.java +++ b/avaje-jex/src/main/java/io/avaje/jex/http/InternalServerErrorException.java @@ -1,9 +1,13 @@ package io.avaje.jex.http; -/** Thrown when unable to find a route/resource */ +/** Thrown when server has an internal error */ public class InternalServerErrorException extends HttpResponseException { public InternalServerErrorException(String message) { super(500, message); } + + public InternalServerErrorException(Object jsonResponse) { + super(500, jsonResponse); + } } diff --git a/avaje-jex/src/main/java/io/avaje/jex/http/NotFoundException.java b/avaje-jex/src/main/java/io/avaje/jex/http/NotFoundException.java index 5a0caa5a..2d5f8213 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/http/NotFoundException.java +++ b/avaje-jex/src/main/java/io/avaje/jex/http/NotFoundException.java @@ -6,4 +6,8 @@ public class NotFoundException extends HttpResponseException { public NotFoundException(String message) { super(404, message); } + + public NotFoundException(Object jsonResponse) { + super(404, jsonResponse); + } } From e96a533a31e5f4e186fe1162f22b89b825b1d09b Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:13:52 -0500 Subject: [PATCH 2/2] test --- .../java/io/avaje/jex/http/BadRequestException.java | 4 ++++ .../io/avaje/jex/core/ExceptionManagerTest.java | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java b/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java index 41548e62..b15f69be 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java +++ b/avaje-jex/src/main/java/io/avaje/jex/http/BadRequestException.java @@ -6,4 +6,8 @@ public class BadRequestException extends HttpResponseException { public BadRequestException(String message) { super(400, message); } + + public BadRequestException(Object jsonResponse) { + super(400, jsonResponse); + } } diff --git a/avaje-jex/src/test/java/io/avaje/jex/core/ExceptionManagerTest.java b/avaje-jex/src/test/java/io/avaje/jex/core/ExceptionManagerTest.java index e555fe6e..3593371f 100644 --- a/avaje-jex/src/test/java/io/avaje/jex/core/ExceptionManagerTest.java +++ b/avaje-jex/src/test/java/io/avaje/jex/core/ExceptionManagerTest.java @@ -1,6 +1,7 @@ package io.avaje.jex.core; import io.avaje.jex.Jex; +import io.avaje.jex.http.BadRequestException; import io.avaje.jex.http.ErrorCode; import io.avaje.jex.http.HttpResponseException; import io.avaje.jsonb.JsonException; @@ -9,6 +10,7 @@ import org.junit.jupiter.api.Test; import java.net.http.HttpResponse; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @@ -34,6 +36,9 @@ static TestPair init() { .put("/nested", ctx -> { throw new JsonException("hmm"); }) + .patch("/patch", ctx -> { + throw new BadRequestException(Map.of("error","bad request")); + }) .error(NullPointerException.class, (ctx, exception) -> ctx.text("npe")) .error(IllegalStateException.class, (ctx, exception) -> ctx.status(222).text("Handled IllegalStateException|" + exception.getMessage())) .error(JsonException.class, (ctx, exception) -> {throw new IllegalStateException();})); @@ -60,6 +65,14 @@ void post() { assertThat(res.body()).isEqualTo("Handled IllegalStateException|foo"); } + @Test + void patch() { + HttpResponse res = pair.request().path("patch").PATCH().asString(); + assertThat(res.statusCode()).isEqualTo(400); + assertThat(res.body()).isEqualTo("{\"error\":\"bad request\"}"); + assertThat(res.headers().firstValue("Content-Type").get()).contains("application/json"); + } + @Test void expect_fallback_to_fallback() { HttpResponse res = pair.request().path("nested").PUT().asString();