Global custom exception handler in resteasy
Asked Answered
C

4

5

Is it possible to make global exception handler for all unexpected errors. Because it's impossible to make all possible classes like this:

public class ExceptionHandler implements ExceptionMapper<JsonMappingException> {...}

I want something like this:

public class ExceptionHandler implements ExceptionMapper<Exception> 
Condensation answered 13/12, 2012 at 10:17 Comment(1)
Shocked that this is not a feature that exists yet... issues.jboss.org/browse/RESTEASY-891Valueless
D
6

You could probably do the following:

@Provider
public class GlobalExceptionHandler implements ExceptionMapper<Exception> {
    public Response toResponse(Exception exception) {
        return Response.status(Status.INTERNAL_SERVER_ERROR)
            .entity("An error occured").type(MediaType.TEXT_PLAIN)
            .build();
    }
}

I have just tested it in RESTEasy 3.0.6.Final and it seems to work. Keep in mind that the 500 Internal Server Error status code may not always be appropriate.

Duress answered 7/7, 2014 at 9:47 Comment(3)
This exception handler overrides all default RESTEasy exception handlers (like NotFoundException handler and many more). That's not really convenient.Impact
A convenient solution may be to use if (exception instanceof NullPointerException) and use multiple else if (...) for different exceptions.Critique
@AlexeiOsipov, check my answer below, it could solve this issue, besides, using custom exceptions is not a bad practice, its I dare say, closer to the Java way of doing things, building on top of other things in a clean way... "Open to Extension, closed to modification"Haplosis
L
11

Note that although the accepted answer does catch all exceptions it will cause many other issues, eg interfering with the internal exception handling of Resteasy.

Therefore if you take this approach you should also build a custom exception mapping for each method that is important for you.

In particular this method will break the built in CORS handling, so you should create a CORS custom exception mapper if you allow CORS responses.

@Provider
public class DefaultOptionsExceptionHandler implements ExceptionMapper<DefaultOptionsMethodException> {

    @Override
    public Response toResponse(DefaultOptionsMethodException e) {
        return e.getResponse(); 
    }
}
Lynseylynus answered 11/7, 2014 at 8:39 Comment(1)
Hi @Lynseylynus I'm experiencing exactly what you describe; instead of defining a mapper for each JAX-RS "system" exception, what would be a better way to create a global exception mapper?Edaphic
D
6

You could probably do the following:

@Provider
public class GlobalExceptionHandler implements ExceptionMapper<Exception> {
    public Response toResponse(Exception exception) {
        return Response.status(Status.INTERNAL_SERVER_ERROR)
            .entity("An error occured").type(MediaType.TEXT_PLAIN)
            .build();
    }
}

I have just tested it in RESTEasy 3.0.6.Final and it seems to work. Keep in mind that the 500 Internal Server Error status code may not always be appropriate.

Duress answered 7/7, 2014 at 9:47 Comment(3)
This exception handler overrides all default RESTEasy exception handlers (like NotFoundException handler and many more). That's not really convenient.Impact
A convenient solution may be to use if (exception instanceof NullPointerException) and use multiple else if (...) for different exceptions.Critique
@AlexeiOsipov, check my answer below, it could solve this issue, besides, using custom exceptions is not a bad practice, its I dare say, closer to the Java way of doing things, building on top of other things in a clean way... "Open to Extension, closed to modification"Haplosis
H
2

How about like what Christian Gürtler answered but with a slight adjustment, instead of using the base exception in the arrow brackets, one can use a custom exception class that extends the base exception class and then one can define all custom exceptions to extend from the custom exception class, this approach should allow you to have generic handlers that do not override handlers for the base Exception class:

@Provider
public class CustomExceptionHandler implements ExceptionMapper<CustomException> {
    @Override
    public Response toResponse(CustomException exception) {
        return Response.status(exception.getErrorType().getHttpStatusCode()).entity(exception.getErrorType().getReason()).build();
    }
}



public class CustomException extends Exception {
    private final CustomError type;
    private Exception innerException;

    public CustomException(CustomError type) {
        super(type.getReason());
        this.type = type;
    }

    public CustomException(CustomError type, Exception e) {
        super(type.getReason()+","+e.getMessage());
        this.type = type;
        this.innerException = e;
    }

    public CustomException(CustomError type, String message) {
        super(type.getReason()+","+message);
        this.type = type;
    }

    public CustomException(CustomError type, String message, Exception e) {
        super(type.getReason()+","+message,e);
        this.type = type;
        this.innerException = e;
    }

    public CustomError getErrorType() {
        return type;
    }
}

public class CustomError {
    private String errorCode;
    private String reason;
    private int httpStatusCode;

    public CustomError(String errorCode, String reason,
                       int httpStatusCode) {
        this.errorCode = errorCode;
        this.reason = reason;
        this.httpStatusCode = httpStatusCode;
    }

    public String getErrorCode() {
        return this.errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getReason() {
        return this.reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public void setHttpStatusCode(int httpStatusCode) {
        this.httpStatusCode = httpStatusCode;
    }

    public int getHttpStatusCode() {
        return this.httpStatusCode;
    }
}
Haplosis answered 30/6, 2022 at 5:32 Comment(0)
C
0

It seems there's no easy way to make it. I have to modify ResteasyProviderFactory which returns right ExceptionMapper. But then I should change couple classes because there's direct usage of build-in class ResteasyProviderFactory

Condensation answered 13/12, 2012 at 14:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.