Issue 1:
srinivas kvs opened SPR-7862 and commented

When the @ExceptionHandler method returns a ResponseEntity, it throws IllegalArgument exception while returning the responsenetity object.

Affects: 3.0.5

Reference URL: http://forum.springsource.org/showthread.php?p=337899#post337899

Issue 2:
Rajeev Sharma opened SPR-7637 and commented

I am new to Spring Framework. I am using @ExceptionHandler to handle exceptions in my controller. I thought the process of returning result from exception handler would be similar to a request handler but that is not the case. Below is my code.

@RequestMapping(value = "/{userid}", method = RequestMethod.GET)
public @ResponseBody
User getUser(@PathVariable(value = "userid") int userId) throws SpringTestException {
logger.trace("Getting user: " + userId);
User user = getUserDAO().getUser(userId);
if (user == null) {
throw new SpringTestException(1000, "User does not exists");
}

logger.trace("Userid: " + user.getId() + ", Name: " + user.getName() + ", Email: "
+ user.getEmailId());
return user;
}

This code fetches user from the database and returns it to the user in json. But when the user is not found in db I through an exception which is handled by an exception class and supposed to return error message in json format ("code": 10000, "message": "user does not exists"}). Below is my exception handler version 1.

@ExceptionHandler(SpringTestException.class)
public @ResponseBody
HttpResponse handleSpringTestException(SpringTestException e) {
logger.trace("Exception caught");
return new HttpResponse(e.getCode(), e.getMessage());
}

HttpResponse has two members "code" and "message".

When I make a curl call, I didn't get the response, instead got an exception with http-status 500.

< HTTP/1.1 500 Internal Server Error

< Server: Apache-Coyote/1.1

< Content-Type: text/html;charset=utf-8

< Content-Length: 2960

< Date: Sun, 10 Oct 2010 12:35:33 GMT

< Connection: close

<

<html><head><title>Apache Tomcat/6.0.20 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.ivasoft.springtest.common.SpringTestException: User does not exists

org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)

org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)

javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

</pre></p><p><b>root cause</b> <pre>com.ivasoft.springtest.common.SpringTestException: User does not exists

com.ivasoft.springtest.controllers.UserControllerIoC.getUser(UserControllerIoC.java:43)

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.lang.reflect.Method.invoke(Method.java:616)

org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:427)

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:415)

org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:788)

org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:717)

org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)

org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)

javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

Closing connection #0

</pre></p><p><b>note</b> <u>The full stack trace of the root cause is available in the Apache Tomcat/6.0.20 logs.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/6.0.20</h3></body></html>

I googled around for hours and found that ExceptionHandlers are handled by different Adaptor than that of request handlers so I need to configure something in my xml file. I did this in my xml config file.

<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter" />

<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />

<bean id="methodHandlerExceptionResolver"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<ref bean="jsonHttpMessageConverter" />
</list>
</property>
</bean>

I got this response after configurations change (This is what I expected):

< HTTP/1.1 200 OK

< Server: Apache-Coyote/1.1

< Content-Type: application/json

< Transfer-Encoding: chunked

< Date: Sun, 10 Oct 2010 12:37:43 GMT

<

Connection #0 to host localhost left intact

Closing connection #0

{"message":"User does not exists","code":1000}

I don't know if the above configuration is correct (This is working but could be a hack found by some developer) as I found it in some forum.

Second level problem came when I used ResposeEntity as return value for my exception handler. I changed the exception handler to this

@ExceptionHandler(SpringTestException.class)
public @ResponseBody
ResponseEntity<HttpResponse> handleSpringTestException(SpringTestException e) {
return new ResponseEntity<HttpResponse>(new HttpResponse(e.getCode(), e.getMessage()),
HttpStatus.NOT_FOUND);
}

And I was exception the same response with status code 404, but got this response.

< HTTP/1.1 200 OK

< Server: Apache-Coyote/1.1

< Content-Type: application/json

< Transfer-Encoding: chunked

< Date: Sun, 10 Oct 2010 12:39:13 GMT

<

Connection #0 to host localhost left intact

Closing connection #0

{"statusCode":"NOT_FOUND","headers":{},"body":{"message":"User does not exists","code":1000}}

Looks like the exception handlers behave differently that request handlers. I fail to understand why is it that way. I used following code to get required results.

@ExceptionHandler(SpringTestException.class)
public @ResponseBody
HttpResponse handleSpringTestException(SpringTestException e, HttpServletResponse response) {
logger.trace("Exception caught");
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return new HttpResponse(e.getCode(), e.getMessage());
}

This makes my code dependent on HttpServletResponse object and this is not the same as what I would do in a request handler. I could use @ResponseBody ResponseEntity as return value to get the same result and that seems correct to me. If exception handlers and request handlers behave the same way it would be much easier and consistent for the framework to work with.

Affects: 3.0.4

2 votes, 2 watchers