I am working on an application which uses Dropwizard, which has this implementation of ExceptionMapper: https://github.com/dropwizard/dropwizard/blob/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/errors/LoggingExceptionMapper.java
Problem with this implementation is that even though this catches both 4** and 5** errors, it only logs 5** errors.
I need to implement ExceptionMapper such that LoggingExceptionMapper is not used at all and my CustomExceptionMapper logs both CLIENT_ERRORs and SERVER_ERRORs.
I am wondering how would my application know that it needs to use CustomExceptionMapper instead of the Dropwizard class?
Also would it suffice to add CLIENT_ERROR to if condition, to log out all errors?
#Override
public Response toResponse(E exception) {
// If we're dealing with a web exception, we can service certain types of request (like
// redirection or server errors) better and also propagate properties of the inner response.
if (exception instanceof WebApplicationException) {
final Response response = ((WebApplicationException) exception).getResponse();
Response.Status.Family family = response.getStatusInfo().getFamily();
if (family.equals(Response.Status.Family.REDIRECTION)) {
return response;
}
if (family.equals(Response.Status.Family.SERVER_ERROR) || family.equals(Response.Status.Family.CLIENT_ERROR) {
logException(exception);
}
return Response.fromResponse(response)
.type(MediaType.APPLICATION_JSON_TYPE)
.entity(new ErrorMessage(response.getStatus(), exception.getLocalizedMessage()))
.build();
}
Or would there be a better way to do this?
JAX-RS spec about ExceptionMapper:
When choosing an exception mapping provider to map an exception, an
implementation MUST use the provider whose generic type is the nearest
superclass of the exception.
How would my application know that it needs to use CustomExceptionMapper instead of the Dropwizard class?
You can throw a custom exception from your application and create an ExceptionMapper for that specific exception.
Would it suffice to add CLIENT_ERROR to if condition, to log out all errors?
Yes, 4xx and 5xx family has all the error responses.
Related
I'm wondering if there is any elegant way to catch all exceptions (specifically custom runtime exceptions) and return an exception containing a list of the messages.
Instead of having a String message, the big exception would then contain String[] message for example.
Scenario:
A REST request is made to the back-end with a JSON object containing a bunch of fields. I want to validate these fields on the backend and return a list of errors if any exceptions occur.
If both the name and lastname field are not acceptable input, I don't want to throw an exception on the invalid name and have the user change the name and submit again only to get an error message that the lastname is invalid too.
Hence why I want to collect all invalid input and return a list of these in the form of an exception.
Spring collects JSR-303/JSR-349 bean validation failures into a BindException:
Thrown when binding errors are considered fatal. Implements the BindingResult interface (and its super-interface Errors) to allow for the direct analysis of binding errors.
Instead of developing your own mechanism for bean validation you might want to read 3. Validation, Data Binding, and Type Conversion and follow the standards.
With Spring Boot, you can use the following annotation to handle any kind of Exception for a class or a method :
#ExceptionHandler(YourExceptionHandler.class)
And you can create a class that let you regroup all your custom exception management like this (if you want to gather it) :
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
You can also implement the interface HandlerExceptionResolver to manage all Exceptions that ARE NOT handled by the Controllers (all the others runtime Exceptions)
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex);
}
Everything is explained in details here : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
EDIT: I just read that you added up scenario. Actually, for your special case, you should just parse the object, and return one exception (like bad object format, along with a 400 HTTP status code error, with a custom message containing all the fields that are invalid. I guess.
In our (legacy) codebase, we're throwing WebApplicationExceptions in different ways.
In an attempt to make some order in how we're handling exceptions - I wanted to create an ExceptionMapper for these WAEs (and others).
I realized, however, that Jersey's ExceptionMapper only maps WAE which weren't thrown with an entity.
For example:
throw new WebApplicationException(Response.status(500).build());
This exception is caught by the ExceptionMapper.
throw new WebApplicationException(Response.status(500).entity(WsResourceUtils.createWSResourceRestError(500, "bla")).build());
This exception is NOT caught by the ExceptionMapper.
Both are thrown from the same point in code.
This is my ExceptionMapper:
#Provider
public class GeneralExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger logger = LoggerFactory.getLogger(GeneralExceptionMapper.class);
#Override
public Response toResponse(Throwable e) {
logger.error("Caught a WAE", e);
...
}
Is it possible to create an ExceptionMapper which will catch WebApplicationExceptions even if their response is already built with an entity?
We're using Jersey 1.17.
Thanks.
This behaviour is describe in the JAX-RS specification and it's still true in version 3.0 :
Instances of WebApplicationException and its subclasses MUST be mapped to a response as follows. If the response property of the exception does not contain an entity and an exception mapping provider (see Exception Mapping Providers) is available for WebApplicationException or the corresponding subclass, an implementation MUST use the provider to create a new Response instance, otherwise the response property is used directly. The resulting Response instance is then processed according to Return Type.
Source : https://jakarta.ee/specifications/restful-ws/3.0/jakarta-restful-ws-spec-3.0.html#method_exc
I don't know why and I think it's not ideal but it's definitely not a bug.
please consider looking at the code in GIST :
https://gist.github.com/jeorfevre/9fb2c447a01bcc724998
Register a Mapper that of MagicException that contains Response
Define Exception that contain response
Throw this exception
I am developing a REST-facade for an EJB service, which means it calls the EJB, translates the result to representations a REST-caller will understand and then returns it (as json or xml). All of that works splendid. But the EJB service throws a variety of exceptions, e. g. when no result is found or a few different other cases. Since I don't want those propagating to the REST-caller, I implemented an ExceptionMapper:
public class EjbExceptionMapper implements ExceptionMapper<EJBException> {
private static final Logger logger = LoggerFactory.getLogger(EjbExceptionMapper.class);
#Override
public Response toResponse(final EJBException exception) {
ResponseBuilder result = Response.status(Status.BAD_REQUEST);
logger.debug("Bad request:", exception);
if (exception.getCause() != null) {
final Throwable cause = exception.getCause();
if (cause instanceof NoDeliveryFoundException) {
logger.debug("Found NoDeliveryFoundException:", cause);
result = Response.status(Status.NO_CONTENT).entity(cause.getMessage());
}
}
return result.build();
}
}
All the exceptions from my EJB-service arrive as javax.ejb.EJBException, which this Mapper manages to catch just fine, with different custom Exceptions of the application as causes. The plan is to return different Responses depending on the type of cause of the EJBException. The logger-calls used for debugging are both executed in case I get a NoDeliveryFoundException as the cause, so I know it's executed (the Mapper registered correctly and is used for mapping), but the client never sees a response.
Every call leading to an EJBException in the underlying service (and thus the use of this ExceptionMapper) leads to no Response at all, as if the toResponse()-method were returning null and not a custom built Response.
I even went so far as to log the Response right before returning it, it exists and contains what I expect, so I am positive that it is returned by the toResponse-method. But still, my client receives no Response.
So now I'm stumped and since no search managed to even find someone describing a similar problem, I turn to you, dear SO. ;)
Your toResponse-method contains some conflicting logic.
Response.status(Status.NO_CONTENT).entity(cause.getMessage());
Here you are assigning the the HTTP status code 204 No Content, but you are also adding a response. You can't set the status to 204 No Content and return a response body at the same time.
Also, if Exception#getCause() is null or if it's not an instance of NoDeliveryFoundException, the response body is empty.
Could this be the cause of your problems?
Is there a way to have global exception handling in Jersey? Instead of individual resources having try/catch blocks and then calling some method that then sanitizes all of the exceptions to be sent back to the client, I was hoping there was a way to put this where the resources are actually called. Is this even possible? If so, how?
Instead of, where sanitize(e) would throw some sort of Jersey-configured exception to the Jersey servlet:
#GET
public Object getStuff() {
try {
doStuff();
} catch (Exception e) {
ExceptionHandler.sanitize(e);
}
}
Having:
#GET
public Object getStuff() throws Exception {
doStuff();
}
where the exception would get thrown to something that I can intercept and call sanitize(e) from there.
This is really just to simplify all the Jersey resources and to guarantee that the exceptions going back to the client are always in some sort of understandable form.
Yes. JAX-RS has a concept of ExceptionMappers. You can create your own ExceptionMapper interface to map any exception to a response. For more info see: https://jersey.github.io/documentation/latest/representations.html#d0e6352
javax.ws.rs.ext.ExceptionMapper is your friend.
Source: https://jersey.java.net/documentation/latest/representations.html#d0e6665
Example:
#Provider
public class EntityNotFoundMapper implements ExceptionMapper<javax.persistence.EntityNotFoundException> {
public Response toResponse(javax.persistence.EntityNotFoundException ex) {
return Response.status(404).
entity(ex.getMessage()).
type("text/plain").
build();
}
}
All the answers above are still valid. But with latest versions of spring Boot consider one of below approaches.
Approach 1 :
#ExceptionHandler- Annotate a method in a controller with this annotation.
Drawback of this approach is we need to write a method with this annotation in each controller.
We can work around this solution by extending all controllers with base controller (that base controller can have a method annotated with #ExceptionHandler. But it may not be possible all the times.
Approach 2 :
Annotating a class with #ControllerAdvice and define methods with #ExceptionHandler
This is similar to Controller based exception (refer approach 1) but this is used when controller class is not handling the exception.
This approach is good for global handling of exceptions in Rest Api
I have an application which consists of SOAP and REST web services and a simple HTTP access. All of them convert incoming requests and send them to a handler. The most painful thing is exception handling. In order to return the right response, I have to wrap every method with try-catch block and create a response there.
I thought that I could create a filter which could do it. But how can the filter recognise the source of it (soap, rest frontend) so I knew that I should return a SOAP or other response?
It depends on the WS framework you use. All I know have some sort of interceptors/aspects that you can inject and handle exceptions in one place. For instance in apache-cxf there is even a special outbound error chain where you can plug your own interceptors.
Obviously try-catch in every method is a bad idea.
In layer of below Web-Service Layer, you have to create your custom Exception and in Web-Service layer you have to use try-catch approach for achieve occurred exception and in catch block log and convert it to your custom web service layer exception. I show this approach in following:
#WebService
public class EmployeeWS
{
#WebMethod
public void add(Employee em) throws CustomWebServiceException
{
try
{
// call facade layer method
}
catch(Exception e)
{
logger.error(e.getMessage());
throw new CustomWebServiceException(e);
}
}
}
Alternative using try catch in any Web-Method,you can use AOP approch(for sample Spring AOP) or interceptor approach in Web-Service frameworks(for sample SOAPHandler<T> in JAX-WS).
Note: In JAX-WS standard, you can't throw a RuntimeException because Exception must specify in final WSDL and if you throw a RuntimeException your web service client don't achieve your CustomException, in another your Web-Methodneed to throws in itself signature.
You can see selected Web-Service faramework documents for more information.
It sounds that you are not using any framework because that was typical frameworks provide. For example Spring allows you to decouple the code from exception handling and define your custom exception handlers.
In your case you generally have 2 solutions.
(1) You can use Decorator pattern: wrap each service with decorator where each method is implemented as
try {
call real method
} catch() {
send error to client
}
Since it is very verbose you can save time using Dynamic proxy (feature that was introduced in java 5). So, you can dynamically wrap each service (if your services have defined interface).
(2) You can solve it using servlet API's error page:
javax.servlet.ServletException
/servlet/ErrorDisplay
for more details see http://java.sun.com/developer/technicalArticles/Servlets/servletapi2.3/
You can customize your class!! Do it!
Take easy on diagnostic errors, like insert a protocol number, message Log, message client, etc...
http://java.globinch.com/enterprise-java/web-services/jax-ws/jax-ws-exceptions-faults-annotation-exception-and-fault-handling-examples/#Pre-Requisites