这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.baeldung.micronaut.globalexceptionhandler;

import io.micronaut.runtime.Micronaut;

public class ServerApplication {

public static void main(String[] args) {
Micronaut.run(ServerApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.baeldung.micronaut.globalexceptionhandler.controller;

import com.baeldung.micronaut.globalexceptionhandler.error.CustomChildException;
import com.baeldung.micronaut.globalexceptionhandler.error.CustomException;

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Error;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Header;
import io.micronaut.http.hateoas.JsonError;
import io.micronaut.http.hateoas.Link;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller("/erroneous-endpoint")
public class ErroneousController {

@Get("/not-found-error")
public HttpResponse<String> endpoint1() {
log.info("endpoint1");

return HttpResponse.notFound();
}

@Get("/internal-server-error")
public HttpResponse<String> endpoint2(@Nullable @Header("skip-error") String isErrorSkipped) {
log.info("endpoint2");
if (isErrorSkipped == null) {
throw new RuntimeException("something went wrong");
}

return HttpResponse.ok("Endpoint 2");
}

@Get("/custom-error")
public HttpResponse<String> endpoint3(@Nullable @Header("skip-error") String isErrorSkipped) {
log.info("endpoint3");
if (isErrorSkipped == null) {
throw new CustomException("something else went wrong");
}

return HttpResponse.ok("Endpoint 3");
}

@Get("/custom-child-error")
public HttpResponse<String> endpoint4(@Nullable @Header("skip-error") String isErrorSkipped) {
log.info("endpoint4");
if (isErrorSkipped == null) {
throw new CustomChildException("something else went wrong");
}

return HttpResponse.ok("Endpoint 4");
}

@Error(exception = UnsupportedOperationException.class)
public HttpResponse<JsonError> unsupportedOperationExceptions(HttpRequest<?> request) {
log.info("Unsupported Operation Exception handled");
JsonError error = new JsonError("Unsupported Operation").link(Link.SELF, Link.of(request.getUri()));

return HttpResponse.<JsonError> notFound()
.body(error);
}

@Get("/unsupported-operation")
public HttpResponse<String> endpoint5() {
log.info("endpoint5");
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.baeldung.micronaut.globalexceptionhandler.controller;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller("/probe")
public class ProbesController {

@Get("/liveness")
public HttpResponse<String> endpoint1() {
log.info("endpoint1");

return HttpResponse.ok();
}

@Get("/readiness")
public HttpResponse<String> endpoint2() {
log.info("endpoint2");

throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.baeldung.micronaut.globalexceptionhandler.error;

public class CustomChildException extends CustomException {
public CustomChildException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.baeldung.micronaut.globalexceptionhandler.error;

public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.baeldung.micronaut.globalexceptionhandler.error.handlers;

import com.baeldung.micronaut.globalexceptionhandler.error.CustomException;

import io.micronaut.context.annotation.Requires;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.server.exceptions.ExceptionHandler;
import jakarta.inject.Singleton;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Produces
@Singleton
@Requires(classes = { CustomException.class, ExceptionHandler.class })
public class CustomExceptionHandler implements ExceptionHandler<CustomException, HttpResponse<String>> {

@Override
public HttpResponse<String> handle(HttpRequest request, CustomException exception) {
log.info("handling CustomException: [{}]", exception.getMessage());

return HttpResponse.ok("Custom Exception was handled");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.baeldung.micronaut.globalexceptionhandler.error.handlers;

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Error;
import io.micronaut.http.hateoas.JsonError;
import io.micronaut.http.hateoas.Link;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller("/notfound")
public class NotFoundController {

@Error(status = HttpStatus.NOT_FOUND, global = true)
public HttpResponse<JsonError> notFound(HttpRequest<?> request) {
log.info("not found error handled");
JsonError error = new JsonError("Page Not Found").link(Link.SELF, Link.of(request.getUri()));

return HttpResponse.<JsonError> notFound()
.body(error);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package com.baeldung.micronaut.globalexceptionhandler;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.is;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;

import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import io.restassured.specification.RequestSpecification;

@MicronautTest
class ServerApplicationUnitTest {

private static final String ERRONEOUS_ENDPOINTS_PATH = "micronaut-configuration-tutorials/erroneous-endpoint";
private static final String PROBES_ENDPOINTS_PATH = "micronaut-configuration-tutorials/probe";

@Test
public void givenNotFoundStatusHandler_whenRequestTheHandlerEndpoint_thenResponseIsNotFound(RequestSpecification spec) {
spec.given()
.basePath("micronaut-configuration-tutorials")
.header("some-header", "some-value")
.when()
.get("/notfound")
.then()
.statusCode(404)
.body(Matchers.containsString("\"message\":\"Page Not Found\",\"_links\":"));
}

@Test
public void givenNotFoundStatusHandler_whenRequestThatThrows404_thenResponseIsHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.when()
.get("/not-found-error")
.then()
.statusCode(404)
.body(Matchers.containsString("\"message\":\"Page Not Found\",\"_links\":"));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatThrowsDifferentError_thenResponseIsNotHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.when()
.get("/internal-server-error")
.then()
.statusCode(500)
.body(containsString("\"message\":\"Internal Server Error\""));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatThrowsDifferentErrorIsSkipped_thenResponseIsNotHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.header("skip-error", true)
.when()
.get("/internal-server-error")
.then()
.statusCode(200)
.body(is("Endpoint 2"));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatThrowsCustomException_thenResponseIsHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.when()
.get("/custom-error")
.then()
.statusCode(200)
.body(is("Custom Exception was handled"));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatThrowsCustomExceptionIsSkipped_thenResponseIsNotHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.header("skip-error", true)
.when()
.get("/custom-error")
.then()
.statusCode(200)
.body(is("Endpoint 3"));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatThrowsCustomChildException_thenResponseIsHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.when()
.get("/custom-child-error")
.then()
.statusCode(200)
.body(is("Custom Exception was handled"));
}

@Test
public void givenCustomExceptionHandler_whenRequestThatIsOK_thenResponseIsNotHandled(RequestSpecification spec) {
spec.given()
.basePath(PROBES_ENDPOINTS_PATH)
.when()
.get("/liveness")
.then()
.statusCode(200)
.body(emptyOrNullString());
}

@Test
public void givenLocalUnsupportedOperationExceptionHandler_whenRequestThatThrowsThisException_thenResponseIsHandled(RequestSpecification spec) {
spec.given()
.basePath(ERRONEOUS_ENDPOINTS_PATH)
.when()
.get("/unsupported-operation")
.then()
.statusCode(404)
.body(containsString("\"message\":\"Unsupported Operation\""));
}

@Test
public void givenLocalUnsupportedOperationExceptionHandler_whenRequestThatThrowsThisExceptionInOtherController_thenResponseIsNotHandled(RequestSpecification spec) {
spec.given()
.basePath(PROBES_ENDPOINTS_PATH)
.when()
.get("/readiness")
.then()
.statusCode(500)
.body(containsString("\"message\":\"Internal Server Error\""));
}
}