0

I'm trying to manage a custom error page with my custom exception. I have this exception

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Inesistente")
public class ResourceNotAccessibleException extends Throwable{

    public ResourceNotAccessibleException(String message){
        super(message);
    }


}

which i want to respond with a 404 error. Than i'm managing an error controller

@ControllerAdvice
public class ErrorController {

@ExceptionHandler({ResourceNotAccessibleException.class})
    public ModelAndView getErrorPage(HttpServletRequest request, Throwable ex) {
        String errorMsg = "";
        int httpErrorCode = getErrorCode(request);


        switch (httpErrorCode) {
        case 404: {

            logger.error("Status Error " + httpErrorCode , ex.getMessage());
            errorMsg = messageSource.getMessage("errorMessage", new Object[] { uuid, +httpErrorCode }, locale);
            break;
        }
        case 400: {
            errorMsg = "BAD REQUEST";
            break;
        }

        case 500: {
            errorMsg = messageSource.getMessage("errorMessage", new Object[] { uuid, +httpErrorCode }, locale);
            logger.error("Status Error " + httpErrorCode , ex.getMessage());
            break;
        }
        }
        ModelAndView mav = new ModelAndView();
        mav.addObject("errorMsg", errorMsg);

        mav.setViewName("error");

        return mav;
    }

Now, in my controller if i have something like

if(object==null) {
throw new ResourceNotAccessibleException("Resource does not exist");
}

I should see my error view, but i'm getting the classic white error page, in my log i see the exception being hit..

MarioC
  • 2,934
  • 15
  • 59
  • 111

2 Answers2

0

The ResourceNotAccessibleException should extend Exception or RuntimeException and not Throwable. More info

If you can't change exception type, probably you could try ExceptionHandlerExceptionResolver or this awesome post about Spring exception handling


One more thing, you probably want to add some @ResponseStatus info above getErrorPage, because you are handling this exeption and @ResponseStatus annotation above the ResourceNotAccessibleException will never trigger.

So i think something like this should work:

@ControllerAdvice
public class ErrorController {

    @ResponseStatus(value= HttpStatus.NOT_FOUND) // <= important
    @ExceptionHandler({ResourceNotAccessibleException.class})
    public ModelAndView getErrorPage(HttpServletRequest request, Throwable ex) {
        String errorMsg = "";

        // ... some code here

        ModelAndView mav = new ModelAndView();
        mav.addObject("errorMsg", errorMsg);

        mav.setViewName("error");

        return mav;
    }
}


public class ResourceNotAccessibleException extends Exception{ // <= important

    public ResourceNotAccessibleException(String message){
        super(message);
    }
}

If this doesn't work, you can also try to change resource view file name to something like errorPage.jsp or errorPage.html and set it like mav.setViewName("errorPage");

varren
  • 14,551
  • 2
  • 41
  • 72
0

You need to replace the default error pages in your web container and map a status code to a particular error page.

Here are the changes you need to make:

  1. If it's a Jetty container, here are the changes:

    @Bean
    public JettyEmbeddedServletContainerFactory 
        containerFactory(
            @Value("${server.port:8080}") final String port,
            @Value("${jetty.threadPool.maxThreads:600}") final String maxThreads,
            @Value("${jetty.threadPool.minThreads:10}") final String minThreads,
            @Value("${jetty.threadPool.idleTimeout:5000}") final String idleTimeout) {
        final JettyEmbeddedServletContainerFactory factory =
                new JettyEmbeddedServletContainerFactory(Integer.valueOf(port));
    
        ...
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, 
             "/error-info.html"));
        ...
        return factory;
    }
    
  2. If it's a Tomcat container, here are the changes:

    @Bean
    public EmbeddedServletContainerCustomizer container() {
         return new EmbeddedServletContainerCustomizer() {
    
            @Override
            public void customize(
                ConfigurableEmbeddedServletContainer container) {
                container.addErrorPages(new 
                    ErrorPage(HttpStatus.NOT_FOUND, "/error-info.html"));
    
            }
        };
    }
    
  3. For your ErrorController, don't set view name. It will pick the view from the error page mapping which was set earlier.

    @ControllerAdvice
    public class ErrorController {
    
        @ExceptionHandler(ResourceNotAccessibleException.class)
        @ResponseStatus(value = HttpStatus.NOT_FOUND)
        public ModelAndView handleResourceNotAccessibleException(
            HttpServletRequest req, ResourceNotAccessibleException ex) {
           ...
           ModelAndView mav = new ModelAndView();
           mav.addObject("errorMsg", errorMsg);
    
           retrun mav;
        }
     }
    
  4. Location of error-info.html or jsp under resources/static

Indra Basak
  • 7,124
  • 1
  • 26
  • 45
  • If you don't want `ErrorInfo`, you can turn it into a`ModelAndView`. In my case, I use a POJO for my REST services. – Indra Basak Sep 18 '17 at 20:39
  • Ok thanks, the problem now is that my ErrorController it's not taken into account, i am redirected directly to the error page – MarioC Sep 19 '17 at 07:15