11

I am building a Spring 4 MVC app. And it is completely configured using Java Annotations. There is no web.xml. The app is configured by using instance of AbstractAnnotationConfigDispatcherServletInitializer and WebMvcConfigurerAdapter like so,

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.example.*"})
@EnableTransactionManagement
@PropertySource("/WEB-INF/properties/application.properties")
public class WebAppConfig extends WebMvcConfigurerAdapter {
...
}

and

public class WebAppInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {
...
}

I am now trying to add a global/catch-all exception handler for 404 pages i.e. HttpStatus.NOT_FOUND but no success. Below are some of the ways I tried.

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

@ControllerAdvice
public class GlobalExceptionHandlerController {

    @ExceptionHandler
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView handleException (NoSuchRequestHandlingMethodException ex) {
            ModelAndView mav = new ModelAndView();
            return mav;
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView handleExceptiond (NoHandlerFoundException ex) {
            ModelAndView mav = new ModelAndView();
            return mav;
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public void handleConflict() {

    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoSuchRequestHandlingMethodException.class)
    public void handlesdConflict() {
    }

}

None of these methods get executed. I am at a loss as to how to handle this. I do not want to use web.xml becasue then I would have to create one just for this.

2
  • I don't know why they didn't make the DispatcherServlet visible through some protected method, but the custom solution seems good. Commented Jul 2, 2014 at 14:51
  • Why dont you just override just createDispatcherServlet Commented Jan 13, 2016 at 7:42

5 Answers 5

15

By default, the DispatcherServlet does not throw a NoHandlerFoundException. You need to enable that.

The AbstractAnnotationConfigDispatcherServletInitializer should let you override how the DispatcherServlet is created. Do that and call

DispatcherServlet dispatcherServlet = ...; // might get it from super implementation
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @Sotirios for the response. But I dont seem to be able to get the dispatcherServlet in AbstractAnnotationConfigDispatcherServletInitializer.
@Chantz Override the registerDispatcherServlet. Look at the implementation of the super type to get an idea of what to do.
One year later... Is there a simpler way of doing this? I usually don't override registerDispatcherServlet in my Initializer so I find this method too verbose. All those lines rewritten just to add one line.
@Link Looking at the source, it doesn't look like they've changed it.
But you can override createDispatcherServlet by adding one more line to it as I mentioned down
7

Enable DispatcherServlet throw a NoHandlerFoundException through web.xml configuartion.

<init-param>
    <param-name>throwExceptionIfNoHandlerFound</param-name>
    <param-value>true</param-value>
</init-param>

Comments

3

Instead overriding registerDispatcherServlet one can override the createDispatcherServlet method as follows.

@Override
    protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
        DispatcherServlet ds = new DispatcherServlet(servletAppContext);
        ds.setThrowExceptionIfNoHandlerFound(true);
        return ds;
    }

Comments

3

I resolved the problem with the following entry in my application.yml

 server.error.whitelabel.enabled: false
 spring.mvc.throw-exception-if-no-handler-found: true

and the following ControllerExceptionHandler:

@ControllerAdvice
public class ControllerExceptionHandler {

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String processMethodNotSupportedException(Exception exception) {
    exception.printStackTrace();
    return "error";
}

}

and last but not least i added a template "/html/error.html"

1 Comment

After SpringBoot version 2.0, using spring.mvc.throwExceptionIfNoHandlerFound: true
0

I can't comment on the above post by @Ysak (reputation<50), however I can confirm that this method does work with the setup described by the OP.

I will add that from another guide I also had the DefaultServletHandling configured in my WebConfig to fix a separate issue, as below:

@Configuration
@EnableWebMvc
@ComponentScan("com.acme.tat.controllers")
public class WebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
...
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
}

}

With this set to enable, there is no Exception thrown. Once I removed this line and set up manual resourceHandlers everything worked as expected.

It took me around 2.5 hours to set up 404 redirecting because of this simple one line method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.