Global error handler with Spring @ControllerAdvice doesn't work

3.4k views Asked by At

Anyone know why the following code failed to capture the exception?

package org.rythmengine.spring.web.servlet.view;

import org.rythmengine.RythmEngine;
import org.rythmengine.exception.RythmException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class RythmExceptionHandler {

    RythmEngine engine;

    @Autowired
    public RythmExceptionHandler(RythmConfigurer conf) {
        this.engine = conf.getRythmEngine();
    }

    @ExceptionHandler(value = RythmException.class)
    public ModelAndView defaultErrorHandler(RythmException e) throws Exception {
        if (engine.mode().isProd()) {
            throw e;
        }
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.setViewName("errors/500.html");
        return mav;
    }

}
1

There are 1 answers

3
Gelin Luo On BEST ANSWER

Found the issue. It needs to add one line in the configuration file:

<context:component-scan base-package="org.rythmengine.spring.web.servlet.view"/>

And also need to add @EnableWebMvc annotation in additional to the @ControllerAdvice annotation.

However I can't force user to add the component in their configuration, or I want to make it transparent to user. Thus the solution become the following code:

    if (engine.isDevMode()) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("org.rythmengine.spring.web.servlet.view");
    }

This is not the end so far. It successfully capture the Exception in user's controller code, but not the exception in the view rendering process. I am looking for a way to add HandlerInterceptor so that it can handle error in DispatcherServlet.triggerAfterCompletion(...)

Updates

The above code proved not working. The final solution is adding the following annotation to an arbitrary class:

@Configuration
@ComponentScan("org.rythmengine.spring.web.servlet.view")

And yes, now I don't need user to add the <context:component-scan ...> into their xml configuration file.

With regarding to render time exception handling, I cache the exception internally in the RythmView class in case there are error (usually compile error or parsing error) raised up at checkResource(Locale) call, and in the following renderMergedTemplateModel call I will check if there are cached exception, if there is then render the exception screen, which is something like:

enter image description here

And yes, the developer friendly screen feature is only available when you set devMode to true (which is by default false) for RythmConfigurer:

<bean id="rythmConfig" class="org.rythmengine.spring.web.servlet.view.RythmConfigurer">
    <property name="resourceLoaderPath" value="/WEB-INF/rythm/"/>
    <property name="outputRequestParameters" value="false"/>
    <property name="devMode" value="true"/>
</bean>