/** * A method available to subclasses for adding default {@link HandlerExceptionResolver}s. * <p>Adds the following exception resolvers: * <ul> * <li>{@link ExceptionHandlerExceptionResolver} * for handling exceptions through @{@link ExceptionHandler} methods. * <li>{@link ResponseStatusExceptionResolver} * for exceptions annotated with @{@link ResponseStatus}. * <li>{@link DefaultHandlerExceptionResolver} * for resolving known Spring exception types * </ul> */ protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver(); exceptionHandlerExceptionResolver.setContentNegotiationManager(mvcContentNegotiationManager()); exceptionHandlerExceptionResolver.setMessageConverters(getMessageConverters()); if (jackson2Present) { List<ResponseBodyAdvice<?>> interceptors = new ArrayList<ResponseBodyAdvice<?>>(); interceptors.add(new JsonViewResponseBodyAdvice()); exceptionHandlerExceptionResolver.setResponseBodyAdvice(interceptors); } exceptionHandlerExceptionResolver.setApplicationContext(this.applicationContext); exceptionHandlerExceptionResolver.afterPropertiesSet(); exceptionResolvers.add(exceptionHandlerExceptionResolver); ResponseStatusExceptionResolver responseStatusExceptionResolver = new ResponseStatusExceptionResolver(); responseStatusExceptionResolver.setMessageSource(this.applicationContext); exceptionResolvers.add(responseStatusExceptionResolver); exceptionResolvers.add(new DefaultHandlerExceptionResolver()); }
@Test public void handlerExceptionResolver() throws Exception { delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer)); delegatingConfig.handlerExceptionResolver(); verify(webMvcConfigurer).configureMessageConverters(converters.capture()); verify(webMvcConfigurer).configureContentNegotiation(contentNegotiationConfigurer.capture()); verify(webMvcConfigurer).configureHandlerExceptionResolvers(exceptionResolvers.capture()); assertEquals(3, exceptionResolvers.getValue().size()); assertTrue(exceptionResolvers.getValue().get(0) instanceof ExceptionHandlerExceptionResolver); assertTrue(exceptionResolvers.getValue().get(1) instanceof ResponseStatusExceptionResolver); assertTrue(exceptionResolvers.getValue().get(2) instanceof DefaultHandlerExceptionResolver); assertTrue(converters.getValue().size() > 0); }
@Test public void handlerExceptionResolver() throws Exception { HandlerExceptionResolverComposite compositeResolver = (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver(); assertEquals(0, compositeResolver.getOrder()); List<HandlerExceptionResolver> expectedResolvers = compositeResolver.getExceptionResolvers(); assertEquals(ExceptionHandlerExceptionResolver.class, expectedResolvers.get(0).getClass()); assertEquals(ResponseStatusExceptionResolver.class, expectedResolvers.get(1).getClass()); assertEquals(DefaultHandlerExceptionResolver.class, expectedResolvers.get(2).getClass()); ExceptionHandlerExceptionResolver eher = (ExceptionHandlerExceptionResolver) expectedResolvers.get(0); assertNotNull(eher.getApplicationContext()); }
@Override public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { exceptionResolvers.forEach(resolver -> { if (resolver instanceof ResponseStatusExceptionResolver) ((ResponseStatusExceptionResolver) resolver).setMessageSource(null); }); }
@Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { // NOTE: Do not change the order! Only first resolution is used. // By default Spring MVC does not log exceptions from @Controller methods. if (!runtimeEnvironmentUtil.isIntegrationTestEnvironment()) { exceptionResolvers.add(new LoggingHandlerExceptionResolver()); } // Process exception using @ExceptionHandler method inside @Controller exceptionResolvers.add(exceptionHandlerExceptionResolver()); // Return status code specified using @ResponseStatus in exception class exceptionResolvers.add(new ResponseStatusExceptionResolver()); // Send HTTP status code depending on the exception which is mapped to error page in web.xml exceptionResolvers.add(new DefaultHandlerExceptionResolver()); }
@Test @SuppressWarnings("unchecked") public void handlerExceptionResolver() throws Exception { ApplicationContext context = initContext(WebConfig.class); HandlerExceptionResolverComposite compositeResolver = context.getBean("handlerExceptionResolver", HandlerExceptionResolverComposite.class); assertEquals(0, compositeResolver.getOrder()); List<HandlerExceptionResolver> expectedResolvers = compositeResolver.getExceptionResolvers(); assertEquals(ExceptionHandlerExceptionResolver.class, expectedResolvers.get(0).getClass()); assertEquals(ResponseStatusExceptionResolver.class, expectedResolvers.get(1).getClass()); assertEquals(DefaultHandlerExceptionResolver.class, expectedResolvers.get(2).getClass()); ExceptionHandlerExceptionResolver eher = (ExceptionHandlerExceptionResolver) expectedResolvers.get(0); assertNotNull(eher.getApplicationContext()); DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(eher); List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyAdvice"); assertEquals(1, interceptors.size()); assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass()); LocaleContextHolder.setLocale(Locale.ENGLISH); try { ResponseStatusExceptionResolver rser = (ResponseStatusExceptionResolver) expectedResolvers.get(1); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); MockHttpServletResponse response = new MockHttpServletResponse(); rser.resolveException(request, response, context.getBean(TestController.class), new UserAlreadyExistsException()); assertEquals("User already exists!", response.getErrorMessage()); } finally { LocaleContextHolder.resetLocaleContext(); } }
@Bean public HandlerExceptionResolverComposite getHandlerExceptionResolverComposite() { HandlerExceptionResolverComposite result = new HandlerExceptionResolverComposite(); List<HandlerExceptionResolver> resolverList = new ArrayList<>(); resolverList.add(new ExceptionHandlerExceptionResolver()); resolverList.add(new ResponseStatusExceptionResolver()); resolverList.add(new Error500Resolver()); resolverList.add(new DefaultHandlerExceptionResolver()); result.setExceptionResolvers(resolverList); return result; }
/** * Initialize a DispatcherServlet instance registering zero or more controller classes * and also providing additional bean definitions through a callback. */ @SuppressWarnings("serial") protected WebApplicationContext initServlet( final ApplicationContextInitializer<GenericWebApplicationContext> initializer, final Class<?>... controllerClasses) throws ServletException { final GenericWebApplicationContext wac = new GenericWebApplicationContext(); servlet = new DispatcherServlet() { @Override protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { for (Class<?> clazz : controllerClasses) { wac.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz)); } Class<?> mappingType = RequestMappingHandlerMapping.class; RootBeanDefinition beanDef = new RootBeanDefinition(mappingType); beanDef.getPropertyValues().add("removeSemicolonContent", "false"); wac.registerBeanDefinition("handlerMapping", beanDef); Class<?> adapterType = RequestMappingHandlerAdapter.class; wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); Class<?> resolverType = ExceptionHandlerExceptionResolver.class; wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); resolverType = ResponseStatusExceptionResolver.class; wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(resolverType)); resolverType = DefaultHandlerExceptionResolver.class; wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(resolverType)); if (initializer != null) { initializer.initialize(wac); } wac.refresh(); return wac; } }; servlet.init(new MockServletConfig()); return wac; }
/** * A method available to subclasses for adding default {@link HandlerExceptionResolver}s. * <p>Adds the following exception resolvers: * <ul> * <li>{@link ExceptionHandlerExceptionResolver} * for handling exceptions through @{@link ExceptionHandler} methods. * <li>{@link ResponseStatusExceptionResolver} * for exceptions annotated with @{@link ResponseStatus}. * <li>{@link DefaultHandlerExceptionResolver} * for resolving known Spring exception types * </ul> */ protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver(); exceptionHandlerExceptionResolver.setApplicationContext(this.applicationContext); exceptionHandlerExceptionResolver.setContentNegotiationManager(mvcContentNegotiationManager()); exceptionHandlerExceptionResolver.setMessageConverters(getMessageConverters()); exceptionHandlerExceptionResolver.afterPropertiesSet(); exceptionResolvers.add(exceptionHandlerExceptionResolver); exceptionResolvers.add(new ResponseStatusExceptionResolver()); exceptionResolvers.add(new DefaultHandlerExceptionResolver()); }