Directly setting deferred result does not return a body

2.4k views Asked by At

I am using Spring Boot 2.0 and have an endpoint in an @RestController that returns a DeferredResult and in some cases (e.g. if the wanted value does not need to be computed) it sets the result on that DeferredResult directly like so:

  @RequestMapping(value = "test")
  public DeferredResult<String> test() {
    DeferredResult<String> returnValue = new DeferredResult<>();
    returnValue.setResult("Hello, World");
    return returnValue;
  }

Unfortunately, the HTTP body that is returned is empty. The status code 200 shows that the request did not time out and if I add a completion handler to the deferred result, the handler is also called.

The issue also is not fixed when I explicitly create a new Thread and set the result on that after a small sleep period.

What do I have to change to let the DeferredResult actually be serialised correctly?

Edit:

As suggested in the comments, I turned on debug logging for Spring MVC and found the following log messages:

DEBUG org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Written [ok] as "text/plain" using [org.springframework.http.converter.StringHttpMessageConverter@6b634d28]
DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

The result seems to be written correctly at first but then a null ModelAndView is returned to the servlet for some reason.

What could cause this?

2

There are 2 answers

0
Lucas Holt On BEST ANSWER

Do you have etags in use? We had this happen and adding

ShallowEtagHeaderFilter.disableContentCaching(request); 

to the controller method seemed to fix the issue.

2
locus2k On

I believe you have to add @ResponseBody to your method:

@RequestMapping(value = "test")
public @ResponseBody DeferredResult<String> test() {
  DeferredResult<String> returnValue = new DeferredResult<>();
  returnValue.setResult("Hello, World");
  return returnValue;
}

The @ResponseBody annotation tells a controller that the object returned is automatically serialized into JSON and passed back into the HttpResponse object.

https://www.baeldung.com/spring-request-response-body