1

I made a project like this sample. So the controllers are like this

package mypackagename.controller;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@RequestMapping("/")
public class StoresRestController {

    @RequestMapping(method = RequestMethod.GET)
    public String stores() {
        return ...
    }

}

I like to handle all throwables and make my customized unified response. The problem is I cannot find a guide or a sample to do this correctly.

First of all, I tried ExceptionHandler, with Throwable, but it didn't work, so I decided to move on. Then, the most close approach that I found is this, so I tried jersey, by adding something like this. But it's not working for all throwables. Also, it's ignoring my controllers, by complaining

o.g.jersey.internal.inject.Providers     : A provider mypackagename.controller.StoresRestController registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider mypackagename.controller.StoresRestController will be ignored. 

I searched for this error and found this, which I'm not using ContainerResponseFilter in my project as I provided the sample above. So I'm clueless. The main problem is how to handle all throwables, but if you can give me some suggestions about how to solve Providers problem, I'll be so appreciated.

Community
  • 1
  • 1
hadilq
  • 1,023
  • 11
  • 25
  • Thank you, I tried @ExceptionHandler as well. But as I understand they're not designed to handle all throwables. – hadilq Mar 19 '17 at 13:49
  • Actually, as I explained I tried ExceptionHandler with throwable, but It didn't work, so I tried to other solutions like jersey. – hadilq Mar 19 '17 at 13:54
  • There isn't any special exception that I want to catch. I want to have a unified response when my app throws any kind of exceptions. For example I don't want 'timestamp' in my response, which is included in the standard spring responses. – hadilq Mar 19 '17 at 13:58
  • First, putting `try-catch` will make my controller ugly! The framework must catch them. This is the purpose of controllers, unless I want to handle everything by myself! Second, what about the exceptions in authorization process, they are not controllers! What about the exceptions of the framework itself? I want to handle all of them in one place and have a unified response. – hadilq Mar 19 '17 at 14:06
  • Thank you for your answer. By sping-boot exception I meant something like 'not found'. For example, I want to change this "{"timestamp":1489933640236,"status":404,"error":"Not Found","message":"No message available","path":"/api/v1/store/245/sfadf"}" to this response "{"message":"No message available"}". Also `@ControllerAdvice` with `@ExceptionHandler` doesn't work with `Throwable.class`, which I test it again. – hadilq Mar 19 '17 at 14:34

3 Answers3

3

In my project I use @ControllerAdvice to handle my exceptions. Here's an example. Hope this helps. Just make sure this class is on your component scan so it gets picked up.

@RestController
@ControllerAdvice
public class StoresExceptionHandler {

    @ExceptionHandler(Throwable.class)
    public ResponseEntity<Object> handleThrowable(final Throwable ex) {
        return new ResponseEntity<Object>("Unable to process request.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
Carlos Cook
  • 141
  • 3
0

Finally this post helped me to handle all Throwables, except authentication exceptions. The important part was to use @EnableWebMvc and ResponseEntityExceptionHandler. To handle authentication exceptions I used this answer. Hope it's helping someone.

Community
  • 1
  • 1
hadilq
  • 1,023
  • 11
  • 25
0

as @carlos-cook said, you could use a @ControllerAdvice and, ProblemDetail defined in RFC 7807 which could look like:

import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(RuntimeException.class)
  public ProblemDetail handleUnexpectedException(RuntimeException rte, WebRequest wr) {
        ProblemDetail pd = this.createProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, rte);
        pd.setType(URI.create("http://your-site.com/internal-server-error"));
        pd.setTitle("Internal server error");
        return pd;
    }

  @ExceptionHandler(YourCustomeException.class)
  public ProblemDetail handleUnexpectedException(YourCustomException rte, WebRequest wr) {
        ProblemDetail pd = this.createProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, rte);
        pd.setType(URI.create("http://your-site.com/custom-error-page"));
        pd.setTitle("Internal server error");
        return pd;
    }
}

Then in your controller you could simply throw YourCustomException

This controller advice will handle every exception and YourCustomException separately.