Announcement Announcement Module
Collapse
No announcement yet.
Improved support for REST API error reporting in Spring 3.2.0.M2 Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Improved support for REST API error reporting in Spring 3.2.0.M2

    Hi,

    I wonder if someone already tried to use the new feature in Spring 3.2.0.M2 release that allows to handle exceptions from any controller in a centralized way and return response object instead of view.

    It seems to work and my @ControllerAdvice contoller @ExceptionHandler method is invoked when exception is thrown from another controller.

    The new feature should also support returning response objects that afterwards should be converted to XML/JSON..., with relevant message convertors, however, I see that spring still return view.

    So, is it something that still not completed, even though, the feature looks resolved, or I have some mistake or missing configuration.

    Here is my exception handler:

    Code:
    @ControllerAdvice
    public class ExceptionHandlerController {
    	
    	@ExceptionHandler(Exception.class)
    	@ResponseBody
    	public ResponseEntity<ErrorMessage> handleException(Exception ex) {
    
                    // My object that should be converted to JSON
    		ErrorMessage errorMessage = new ErrorMessage();
    		errorMessage.set...
    		
    		ResponseEntity<ErrorMessage> responseEntity = 
    				new ResponseEntity<ErrorMessage>(errorMessage, HttpStatus.INTERNAL_SERVER_ERROR);
    
    		return responseEntity;
    	}
    }
    And mvc configuration:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:security="http://www.springframework.org/schema/security"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xsi:schemaLocation="
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
    		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
    
    	<security:global-method-security pre-post-annotations="enabled" >
    		<security:expression-handler ref="expressionHandler" />
    	</security:global-method-security>
    	
    	<bean id="expressionHandler"
          class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
            <property name="permissionEvaluator" ref="customExpressionHandler"/>
      	</bean>
      	
      	<bean id="customExpressionHandler" 
      		class="my.CustomPermissionEvaluator"/>
    		
    	<context:component-scan base-package="my" use-default-filters="false">
    		<context:include-filter type="regex" expression="\..*\.controller\..*"/> 
    		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    	</context:component-scan>
    	
    	<mvc:annotation-driven conversion-service="conversionService" />
    	
    	<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
            <property name="formatters">
            	<set>
            		<bean class="my.OidParamAnnotationFormatterFactory"/>
            		<bean class="my.FilterParamAnnotationFormatterFactory"/>
            	</set>
            </property>
        </bean>
    </beans>


    Thanks,
    Pavel
    Last edited by pavel.orehov; Nov 8th, 2012, 01:36 AM.

  • #2
    I actually see that the call to my ExceptionHandlerController method is called from ExceptionHandlerExceptionResolver which does not support returning response body. Instead the call should be handled by AnnotationMethodHandlerExceptionResolver which has new method handleResponseBody.

    As far as I understand AnnotationMethodHandlerExceptionResolver should be defined automatically by spring and called when there si @ResponseBody annotation, however, that does not happen in my flow.

    It is a BUG or something that should be fixed in 3.2.0 GA ?

    BTW: Tried 3.2.0.RC1, the same issue.

    Comment


    • #3
      Thanks for trying 3.2.

      Originally posted by pavel.orehov View Post
      I actually see that the call to my ExceptionHandlerController method is called from ExceptionHandlerExceptionResolver which does not support returning response body. Instead the call should be handled by AnnotationMethodHandlerExceptionResolver which has new method handleResponseBody.
      ExceptionHandlerExceptionResolver is the right class to use! See the what's new in Spring 3.1 comment for an explanation on that vs AnnotationMethodHandlerExceptionResolver.

      @ResponseBody is indeed supported. However, in this case you're returning ResponseEntity. They mutually exclusive. Either return an Object from an @ResponseBody method, or return a ResponseEntity, not both. There is no need to have @ResponseBody in this case. ResponseEntity is enough.

      That said, @ResponseBody should be getting ignored in this case and the ResponseEntity should be used to write to the response with message converters. Are you saying that's not the case? Can you provide some log output with org.springframework.web set to DEBUG or if it is reproducible, just create a repro project.

      Comment


      • #4
        Changing the code to @ResponseBody only fixed the problem, however, I had to add @ResponseStatus as well, otherwise I got 200 OK for error.

        Worth to mention that in documentation and thanks a lot for your help

        Code:
        @ControllerAdvice
        public class ExceptionHandlerController {
        	
        	@ExceptionHandler(Exception.class)	
                @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
        	public @ResponseBody ErrorMessage handleException(Exception ex) {
        
                        // My object that should be converted to JSON
        		ErrorMessage errorMessage = new ErrorMessage();
        		errorMessage.set...
        		
        		return errorMessage;
        	}
        }

        Comment

        Working...
        X