#ExceptionHandler not firing - java

This has been asked a few times in Google-land, but I can't seem to apply those resolutions to my situation. My J2EE application uses Spring and I was previously using SimpleMappingExceptionResolver to intercept Exceptions to show a friendly error page for my users. One of the guys on my team has his own package and is using an extended Exception class as a vehicle to communicate validation errors to his users. So now every time a user enters invalid data, it triggers an exception page. He refuses to change his code (even though I thing he should), so now I am forced to make error handling a package- or controller-specific thing.
I've tried to leverage the #ExceptionHandler annotation to do this, but it doesn't seem to be firing. What am I doing wrong? I am expecting a call to dmapproval to essentially return the applicationError view.
Here is my controller:
#Controller
public class ExecutiveApprovalController {
/*omitted stuff*/
#ExceptionHandler(Exception.class)
public String routToErrorHandler(Exception anExc) {
return "applicationError";
}
#RequestMapping(value = "/dmapproval", method = RequestMethod.GET)
public String dmApproval(Model model, HttpServletRequest request) throws Exception {
throw new RuntimeException(); // just for testing exception logic
}
/*omitted stuff here, too*/
}
Thanks for your help!!

Your snippet looks fine; the only difference between your code and something that I have working is that I annotate the exception handler method like this:
#ExceptionHandler(Throwable.class)
As an aside; this is far less elegant than using SimpleMappingExceptionResolver (which it sounds like you already know!). I'd ask you rogue team-mate to reconsider his validation approach and use Exceptions only in exceptional circumstances ;)

Did you add this config in your servlet-context.xml
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">

Related

How do I change only the status code on a Spring MVC error with Boot?

I'm writing a Web application that makes downstream calls using RestTemplate. If the underlying service returns a 401 Unauthorized, I want to also return a 401 to the calling application; the default behavior is to return a 500. I want to keep the default Spring Boot error response as provided by BasicErrorController; the only change I want is to set the status code.
In custom exceptions, I'd just annotate the exception class with #ResponseStatus, but I can't do that here because HttpClientErrorException.Unauthorized is provided by Spring. I tried two approaches with #ControllerAdvice:
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void returnsEmptyBody(HttpClientErrorException.Unauthorized ex) {
}
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void doesNotUseBasicErrorController(HttpClientErrorException.Unauthorized ex) {
throw new RuntimeException(ex);
}
How can I configure MVC to continue to use all of the built-in Boot error handling except for explicitly overriding the status code?
The below code works for me -- in an app consisting of a #RestController whose one method consisted of throw new HttpClientException(HttpStatus.UNAUTHORIZED), running on an embedded Tomcat. If you're running on a non-embedded Tomcat (or, I suspect, on an embedded non-Tomcat) odds are you'll have to do something at least somewhat different, but I hope this answer is at least somewhat helpful anyway.
#ControllerAdvice
public class Advisor {
#ExceptionHandler(HttpClientException.class)
public String handleUnauthorizedFromApi(HttpClientException ex, HttpServletRequest req) {
if (/* ex instanceof HttpClientException.Unauthorized or whatever */) {
req.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 401);
}
return "forward:/error";
}
}
Explanation: when a HttpClientException is thrown while we're processing request X (in an embedded servlet), what normally happens is that it bubbles all the way up to some org.apache class. (I might fire the debugger up again and work out which one, but this is a pretty high-level explanation so it doesn't matter much.) That class then sends request X back to the application, except this time the request goes to "/error", not to wherever it was originally going. In a Spring Boot app (as long as you don't turn some autoconfiguration off), that means that request X is ultimately processed by some method in BasicErrorController.
OK, so why does this whole system send a 500 to the client unless we do something? Because that org.apache class mentioned above sets something on request X which says "processing this went wrong". It is right to do so: processing request X did, after all, result in an exception which the servlet container had to catch. As far as the container is concerned, the app messed up.
So we want to do a couple of things. First, we want the servlet container to not think we messed up. We achieve this by telling Spring to catch the exception before it reaches the container, ie by writing an #ExceptionHandler method. Second, we want the request to go to "/error" even though we caught the exception. We achieve this by the simple method of sending it there ourselves, via a forward. Third, we want the BasicErrorController to set the correct status and message on the response it sends. It turns out that BasicErrorController (working in tandem with its immediate superclass) looks at an attribute on the request to determine what status code to send to the client. (Figuring this out requires reading the class's source code, but that source code is on github and perfectly readable.) We therefore set that attribute.
EDIT: I got a bit carried away writing this and forgot to mention that I don't think using this code is good practice. It ties you to some implementation details of BasicErrorController, and it's just not the way that the Boot classes are expected to be used. Spring Boot generally assumes that you want it to handle your error completely or not at all; this is a reasonable assumption, too, since piecemeal error handling is generally not a great idea. My recommendation to you -- even if the code above (or something like it) does wind up working -- is to write an #ExceptionHandler that handles the error completely, meaning it sets both status and response body and doesn't forward to anything.
You can customize the error handler of the RestTemplate to throw your custom exception, and then handle that exception with the #ControllerAdvice as you mentioned.
Something like this:
#Configuration
public class RestConfig {
#Bean
public RestTemplate restTemplate(){
// Build rest template
RestTemplate res = new RestTemplate();
res.setErrorHandler(new MyResponseErrorHandler());
return res;
}
private class MyResponseErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
if (HttpStatus.UNAUTHORIZED.equals(response.getStatusCode())) {
// Throw your custom exception here
}
}
}
}

Spring Boot HTTP status without throwing exceptions

I want to return HTTP status other than 200 without using the #ExceptionHandler annotation.
The reason for this is that not every call to my application, which results in a status which is not OK should throw an exception, at least not in my opinion.
As an example, if a user is trying to log into the system, but provides an inaccurate password, I see no reason to throw an exception over this just in order to be able to return a 401 status. Instead, I would like to be able to return the status from within a "regular" method.
The reason behind this is that throwing unnecessary exceptions both clutters my log files, and "uses" my log aggregator (Rollbar/Sentry) monthly allowance.
I've tried annotating methods with #ResponseStatus and #ResponseBody, but it didn't work.
I looked around for blog posts or other articles on the issue but couldn't find anything.
Any idea if this is possible?
You can use RessponseEntity. Replace the /*STATUS CODE*/ with whatever you want:
#GetMapping("/url")
#ResponseBody
public ResponseEntity<?> handlerMethod(/*parameters*/) {
// ...
return ResponseEntity.status(/*STATUS CODE*/).body(...);
}
Have a look at the following example
#RestController
public class HelloWorldController {
#GetMapping("/hello")
public ResponseEntity<String> sayHello() {
return ResponseEntity.status(HttpStatus.CREATED).body("Hello World!");
}
}

Custom Annotation Spring MVC ResultBinding

I have a simple MVC controller that I annotate with my custom annotation:
#PreAuthorize("hasRole('GESTION_BENEFICIAIRE')")
#AuthentificationForte(otp = "#{args[0]}",transactionId="#{args[1]}")
#RequestMapping(value = "/ajouter", method = { RequestMethod.POST, RequestMethod.GET })
public String addBeneficiaire(#ModelAttribute("beneficiaireForm") BeneficiaireForm beneficiaireForm,
BindingResult result, Model model, Principal principal) {
[...]
}
My custom annotation is linked with an aspect that throws a RuntimeException when the validation doesn't succeed.
#Around(value = "#annotation(annotation)")
public Object verifyOtp(final ProceedingJoinPoint jointPoint,
final AuthentificationForte annotation) throws Throwable {
try {
if (authentificationForteEnabled) {
[...]
} else {
throw new AuthentificationForteException();
}
} else {
return jointPoint.proceed();
}
} finally {
}
}
So now the behavior is that when the validation fails, I am redirected to a 500 Error page. My goal is to stay in the same page and add a rejected message to the BindingResult:
result.rejectValue("suiteRib", "BeneficiaireForm.InvalidRib");
I haven't found a way to do that, the only way that I've found is to change all my logic and not use the annotation, while using a validation service with a try/catch in the controller code.
Is there any way to handle this and to access the binding result and add the error message when the aspect throws this exception?
Most definitely.
There is an example here of manipulating args:
Aspectj overwrite an argument of a method
You can also autowire services into the aspect class (remember to mark it #Configurable).
If you know the arguments before hand, then I think they can be included into the point cut definition, in which case they can be referred to directly in the around method. This is much nicer was as the arguments come strongly type.
You can read more here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
May be its too late to answer your question but there are two ways you can handle it :
Have a try catch around proceed() in your aspect and when you get runtime exception you can either return the response from the aspect ( like a generic JSP showing the cause of error or generic JSON with error message.)
Second option could be to use Spring Exception Handler Controller advice. Spring MVC provides nice exception handler controller mechanism to call specific handler method for given type of exception class. ( Here is the blog link : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc )
We currently have an application where we use mix of this approach to handle exception.

What are some options for java messaging from service layer to front end

So in my Service layer I have some logic that does some stuff. Sometimes it has to check to see if something is possible before it does it OR it just has to get some OK from the front end ("Are you sure you want to do this?" kind of stuff). The front end, of course, sends a transaction to the screen to get the info.
In the past I have used RuntimeExceptions for this. I will throw a
new MessageException("are.you.sure");
and then the controller level will do a
try{
theService.doSomething();
}catch(MessageException me) {
model.addAttribute(me.getMessageKey());
result.addError(new ObjectError());
}
In another application I made a PostOffice object and would put letters and such in it for messages. It was quite elaborate and very nice, but my new app is much smaller and I don't want all that.
So I am looking for some best practices. How do you guys send messages from the service layer to the front end? And keep in mind, I am NOT talking about Exceptions! I am just talking about messages from the service layer.
One beautiful thing about Spring MVC is the Exception handling. Since the DispatcherServlet has a try-catch(Exception) wrapping the handler method (ie. your controller method), it can catch all exceptions thrown and handle them with #ExceptionHandler methods or some other construct (there are alternatives).
What I've started doing is making my Service methods only throw RuntimeException instances (works well with #Transactional) and define all my #ExceptionHandler methods in a #ControllerAdvice annotated class. Something like:
#ControllerAdvice
public class ControllerHandler {
private static final Logger logger = LoggerFactory.getLogger(ControllerHandler.class);
#ExceptionHandler(value = AuthenticationException.class)
public String handleAuthenticationException(AuthenticationException e) {
if (logger.isInfoEnabled()) {
logger.info("An AuthenticationException occurred: {}", e.getMessage());
}
return "redirect:/";
}
...more
}
#ExceptionHandler annotated methods have a few rules, but are very customizable. You can see all possibilities in the javadoc here. You should also take a look at ResponseStatus.
Personally, I rarely throw checked exceptions from my service layer. The only one that often appears is IOException (parsing JSON, opening files) and even that I like to wrap in a RuntimeException, because it's not like I can do anything special about it at that level.

Spring 3 controller exception handler implementation problems

I was hoping to implement a single "ExceptionController" to handle exceptions that are thrown in execution of my other controllers' methods. I hadn't specified any HandlerExceptionResolver in my application context so according to the API documentation the AnnotationMethodHandlerExceptionResolver should be started. I verified it as such in the source. So why doesn't the following work?
#Controller
public class ExceptionController {
#ExceptionHandler(NullPointerException.class)
public ModelAndView handleNullPointerException(NullPointerException ex) {
// Do some stuff
log.error(logging stuff)
return myModelAndView;
}
}
#Controller
public class AnotherController {
#RequestMapping(value="/nullpointerpath")
public String throwNullPointer() {
throw new NullPointerException();
}
}
I see in the debug logs that the three default exception handlers are asked for handling of the exception, but nothing is done and I see "DispatcherServlet - Could not complete request". Followed by the user being displayed the stacktrace and a 500 Internal error.
Make sure your Exception handler is returning a view that exists/maps to a handler.
You should write your exceptionhandler to the same class with which you want to handle, like the following.
#Controller
public class AnotherController {
#ExceptionHandler(NullPointerException.class)
public ModelAndView handleNullPointerException(NullPointerException ex) {
// Do some stuff.
log.error(logging stuff)
return myModelAndView;
}
#RequestMapping(value="/nullpointerpath")
public String throwNullPointer() {
throw new NullPointerException();
}
}
I don't think this is a good design. Controllers in Spring handle HTTP requests and map to URLs. I don't think "exception" fits into either bin. It feels like a misuse of Spring to me.
An exception is not an HTTP request. You don't map an exception to a URL. Therefore I'd conclude that controllers aren't intended to be treated as exception handlers.
Controllers are a part of the Spring API, but your design isn't using them as intended, so that's why it's not working. Re-think your design.

Categories