Deferred Result in Spring MVC returning incorrect response
java, spring-mvc
Solution
The response body you are getting
{"setOrExpired":true}
indicates that Spring serialized your `DeferredResult` (which has various properties including `setOrExpired`) to JSON instead of handling it with a `DeferredResultMethodReturnValueHandler`. In other words, it used another `HandlerMethodReturnValueHandler`, most likely `RequestResponseBodyMethodProcessor` (which handles `@ResponseBody`), to handle the value returned from your `@RequestMapping` annotated handler method. (The simplest way to test this is to see what happens when you remove the `@ResponseBody` annotation.)
Looking at the 3.2.x source code of `RequestMappingHandlerAdapter`, which registers the default `HandlerMethodReturnValueHandler` instances, the `DeferredResultMethodReturnValueHandler` is registered before `RequestResponseBodyMethodProcessor` and therefore will handle the `DeferredResult` return value first.
Since you're seeing different behavior, we must assume your configuration is not what you've shown here. (Note that `<mvc:annotation-driven/>` registers a `RequestMappingHandlerAdapter`.)
Also note that you are currently loading the configuration in `/WEB-INF/app-servlet.xml` twice, once by the `ContextLoaderListener` and once by the `DispatcherServlet`.
Get rid of your `ContextLoaderListener` and the corresponding `context-param` entirely. They are not needed in your example.
Problem
I am using spring mvc 3.2.4 and jquery 1.9.0 for long polling. My application is deployed on Tomcat 7.0.42. My spring configuration files are as below: Application Web.xml ``` <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee" version="3.0"> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <servlet> <servlet-name>app</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/app-servlet.xml </param-value> </context-param> </web-app> ``` Spring Configration xml as:- ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:annotation-config/> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <context:component-scan base-package="com.webchat"/> <bean id="defferedResult" class="com.exp.DeferredResultContainer"></bean> </beans> ``` Controller for Posting data looks as ``` @RequestMapping(value = "/postComment", method = RequestMethod.POST) public @ResponseBody String postComment(HttpServletRequest request) { deferredResultContainer.updateAllResults(request.getParameter("comment")); return "success"; } ``` Deferred Result container class ``` public class DeferredResultContainer { private final Set<DeferredResult<String>> deferredResults = Collections.synchronizedSet(new HashSet<DeferredResult<String>>() ); public void put(DeferredResult<String> deferredResult){ deferredResults.add(deferredResult); } public void updateAllResults(String value){ for (DeferredResult<String> deferredResult : deferredResults){ deferredResult.setResult(value); } } public void remove(DeferredResult<String> deferredResult){ deferredResults.remove(deferredResult); } public int determineSize(){ return deferredResults.size(); } } ``` Controller for Deferred Result looks as ``` @RequestMapping(value = "/getComments", method = RequestMethod.GET) @ResponseBody public DeferredResult<String> getComments() throws Exception{ final DeferredResult<String> deferredResult= new DeferredResult<String>(); deferredResultContainer.put(deferredResult); deferredResult.onTimeout(new Runnable() { @Override public void run() { deferredResultContainer.remove(deferredResult); } }); deferredResult.onCompletion(new Runnable() { @Override public void run() { deferredResultContainer.remove(deferredResult); } }); return deferredResult; } ``` When I am trying to long poll it through ajax i am getting following response :- ``` {"setOrExpired":false} ``` And onCompletion method is also not getting executed. To Simply things below controller gives perfect response as {"1":"2"} ``` @RequestMapping(value = "/test1", method = RequestMethod.GET) @ResponseBody public Map test1() throws Exception{ Map m1 = new HashMap<String, Object>(); m1.put("1", "2"); return m1; } ``` Once i change it to below and add Deferred result i get response as {"setOrExpired":true} ``` @RequestMapping(value = "/test", method = RequestMethod.GET) @ResponseBody public DeferredResult<Map> test() throws Exception{ DeferredResult<Map> result = new DeferredResult<Map>(); Map m1 = new HashMap<String, Object>(); m1.put("1", "2"); result.setResult(m1); return result; } ``` Polling code ``` $(document).ready(function() { longPoll(); function longPoll(){ $.support.cors = true; var path = "http://localhost:8080/WebChatExp/rest"; $.ajax({ url: path + "/getComments", cache:false, success: function(data){ //To Do alert("Data" + JSON.stringify(data)); }, error: function(err, status, errorThrown ) { }, type: "GET", dataType: "json", complete: longPoll, timeout: 60000 // timeout every one minute }); } ``` I have searched various examples but cannot figure out if any extra configuration is required for deferred result. Please advise.