I found another post showing how we can create our own checked exceptions that also return a HTTP status code different from 500. However, I need it to be a RuntimeException.
Then, I found WebApplicationException which is an unchecked exception, returns a HTTP status code but does not allow me to set message as in a regular exception.
Is there any unchecked exception out there in Java EE 6 that allows me to set an error message like in a regular exception and also returns a HTTP status code that I can set?
Edit: Including an explanation of why I want this as requested by John.
I created a filter to catch HTML and XSS attacks from my requests parameters. Instead of checking for that everytime in Filter.doFilter which would be too slow, I extended HttpServletRequestWrapper and used it like this.
HttpFilterRequest implements Filter
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(new SafeHttpRequest((HttpServletRequest) request), response);
} catch (SecurityViolationException e) {
log.warn(format("A security violation was detected. Please enable debug for further details: %s]", e.getMessage()));
HttpServletResponse resp = (HttpServletResponse) response;
resp.sendError(e.getStatusCode());
}response);
}
SafeHttpRequest extends HttpServletRequestWrapper (supressing parts to shorten code)
#Override
public String getParameter(String parameter) {
return xssAndHtmlValidation(super.getParameter(parameter));
}
#Override
public String getHeader(String name) {
return xssAndHtmlValidation(super.getHeader(name));
}
xssAndHtmlValidation() throws SecurityViolationException which is a RuntimeException but the catch block at doFilter doesn't work because my exception is thrown as a ServletException containing SecurityViolationException.
Ok, so the issue is that you want SafeHttpRequest.xssAndHtmlValidation() to throw an exception that can pass out of HttpServletRequest.getParameter() and HttpServletRequest.getHeader(), neither of which declares any checked exceptions. You want this exception ultimately to be caught by HttpFilterRequest.doFilter(). You want it to have a customizable message and you want it to carry an HTTP response code.
You clearly do need an unchecked exception to approach the problem this way. It seems most appropriate to create a new one from scratch, by extending java.lang.RuntimeException. You can give that class whatever fields, constructors, and methods you want, by which to transport any information at all from xssAndHtmlValidation() to the filter. Doing so for an exception class is no different from doing so for any other class, though your constructors should be sure to invoke an appropriate superclass constructor.
The filter must then have a catch block for the new custom exception type. Since it is your own custom exception, it is unlikely to be caught by anything between the request and the filter, and since you will catch that specific exception, you can easily invoke whatever nice methods you provided for yourself, such as maybe a getResponseCode(). Presumably the catch block would then invoke one of the sendError() methods on the response object, and then return normally rather than throwing an exception up the stack.
Do note, by the way, that if the problem is detected too late, after the underlying resource has already committed to a different response, then attempting to sendError() will cause an IllegalStateException instead of changing the response code. The client won't see that (because, again, the response has already been committed), but the response might be truncated.
Note also that it is unclear whether you actually need your custom exception to carry an HTTP response code. Would it ever vary from one instance to another? If not, then the appropriate response code is inherent in the fact that the exception was thrown at all, and the filter can set a response code appropriately based solely on the fact that it has caught that particular exception type.
Update:
Of course, if your JSP engine is going to wrap your exception and throw it as a ServletException then you can catch that exception and decide what to do based on exception.getCause().getClass() (but do watch out for the cause being null). That could work if the engine has not already committed the response in such cases.
If your JSP engine is after all going to intercept all exceptions and convert them into HTTP code 500 responses, then any approach based on throwing an exception is simply a dead end. Your best option then is to handle it on the front end, in your filter, before passing the request down the chain. That's a natural fit for a filter.
You expressed concern that doing the test in the filter would be too slow, but that could be slower than your proposed alternative only if the request contains parameters or headers that are never examined by downstream components. On the other hand, your approach based on a request wrapper could in fact be the slower one if request headers or parameters are accessed more than once each downstream, as you will perform the validation on each access, even though you only need to perform it once per parameter / header.
Related
is there a way to ignore the validation done through annotation? In the project that I am working at the moment there is the need to work with predefined generated entities that have some annotated validation, such a email, length, etc.
I want to be able to ignore this validation that is performed through the entity. If this is not possible, I am already able to catch the exception in my exception handler through ControllerAdvice, but I am unable to find a way to get the object that was sent through there. Is this even possible?
This is my handler for it:
#ExceptionHandler(value = {MethodArgumentNotValidException.class, ConstraintViolationException.class})
public final ResponseEntity handleValidationExceptions(HttpServletRequest request, HttpServletResponse response,
Object handler) throws IOException {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Not ok");
}
I though about intercepting the request with preHandle as well, but then I come to the same issue of how to get the sent object in there. Through the HandlerMethod I know I can see the args that the method will receive but I can't find the request anywhere.
This would also be a suitable solution since I can just perform what I have to do over there and then "resume" the execution to the main method.
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.
I am using Play framework (2.5) for Java development. In that, we configure routes and for those routes the relative controller methods to be triggered.
I have a question whether is it OK to include exception throws in these controller method signatures or we must catch them inside the method body?
EX:
public Result getPurchasedStatisticsOutOfAllPriceChecked(String from, String to) throws InvalidParameterException, SalesServiceException {
RequestParams requestParams = new RequestParams(messageProvider);
requestParams.setDateRangeStart(from);
requestParams.setDateRangeEnd(to);
return ok(processInfluenceOnSales(influenceOnOverallSales));
}
I think the better way is to handle those Exceptions inside your Action method, instead of throwing. By this you can respond to the client with relevant error message, otherwise you end up with
500 Internal server error
and your stacktrace looks like following play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception followed by respective exception trace.
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?
My Spring MVC app is full of methods that look like this:
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public final void foo(HttpServletRequest request, ModelMap modelMap){
try{
this.fooService.foo();
}
catch (Exception e){
log.warn(e.getMessage(), e);
}
}
Exceptions are caught and logged but not handled otherwise.
The fooService called above does the same thing, never throwing exceptions up to the controller but catching and logging them. So, actually this controller exception code will never get invoked.
What's the best and simplest approach to implement proper exception handling in my app?
Get rid of all catch statements if all they do is logging carelessly. catch is meant to handle the error, not hide it.
Once all these catches are removed, install one global exception resolver in Spring MVC (1, 2, 3, ...) Simply implement this trivial interface:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
In your exception resolver you might simply log the exception once and let it go as unprocessed (return null), so that error mappings in web.xml will forward request to proper error page. Or you can handle exception yourself and render some error page. AFAIK in simplest case there is no need for register exception resolver, just define it as a Spring bean/annotate with #Service.
Remember, catch the exception only when you know what to do with. Logging is only for troubleshooting, it doesn't handle anything.
BTW this:
log.warn(e.getMessage(), e);
is not only a very poor exception handling, but it is also slightly incorrect. If your exception does not have a message, you will see mysterious null just before the stack trace. If it does, the message will appear twice (tested with Logback):
22:51:23.985 WARN [main][Foo] OMG! - this is the exception message
java.lang.IllegalStateException: OMG! - this is the exception message
at Foo.bar(Foo.java:20) ~[test-classes/:na]
...sometimes undesirable, especially when exception message is very long.
UPDATE: When writing your own exception logger consider implementing both org.springframework.web.servlet.HandlerExceptionResolver and org.springframework.core.Ordered. The getOrder() should return something small (like 0) so that your handler takes precedence over built-in handlers.
It just happened to me that org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver running prior to my handler returned HTTP 500 without logging the exception.