Spring Ajax @ResponseBody with null returned values
Solution 1
This is not a trivial problem to solve.
Spring has a common pattern in which if a handler method returns null
, it is meant to indicate that the handler has already dealt with producing and writing the appropriate response content and that no further action is necessary on the front.
Spring has applied this pattern in its RequestResponseBodyMethodProcesser
(the HandlerMethodReturnValueHandler
implementation for @ResponseBody
). It checks if the return value is null
. It sets the request as handled. If the return value is not null
, it attempts to serialize it with an appropriate HttpMessageConverter
.
One option is to create your own @ResponseBodyNull
annotation and a corresponding HandlerMethodReturnValueHandler
which does the same except also handles null
. Note that you can't necessarily reuse the code from RequestResponseBodyMethodProcess
because some HttpMessageConverters
would fail trying to use null
.
Another similar option is to override RequestResponseBodyMethodProcessor
to accept null
(with the limitations stated above) and register it explicitly with your RequestMappingHandlerMapping
, overwriting the default HandlerMethodReturnValueHandler
s. You have to do this carefully (ie. register the same ones), unless you want to lose functionality.
The better solution, IMO, would be to not deal with null
in the response body. If getObject
doesn't return anything, that seems like a 404 to me. Set the appropriate response code and voila!
You can always inject the HttpServletResponse
into your handler method and do something like
Object object = getObject(..);
if (object == null) {
response.getWriter().print("null");
// also set the content type to application/json
}
return object;
Assuming you knew that this had to be serialized to JSON.
Solution 2
You can return a ResponseEntity and specify the HTTP status to an error when the object is null:
@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
public ResponseEntity<Object> getObject(@RequestParam("id") Long id) {
Object object = provider.getObject(id);
if (object == null ) {
return new ResponseEntity<Object> (HttpStatus.BAD_REQUEST); // Or any other error status
} else {
return new ResponseEntity<Object> (object, HttpStatus.OK);
}
}
In this way your client will be able to know when the object is null checking the response status.
If you actually need the null value returned you can configure Jackson to serialize it (code from tkuty):
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
I hope this help you.
fashuser
Updated on June 25, 2022Comments
-
fashuser almost 2 years
I have about fifty controllers that use @ResponseBody annotation.
Like this:
@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) public @ResponseBody Object getObject(@RequestParam("id") Long id) { Object object = provider.getObject(id); return object; }
Some times getObject method return
null
. The issues is that on client side I get empty response instead ofnull
.In the initial implementation we have custom
JsonView
object that works as wrapper without @ResponseBody annotation.Like this:
@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) public JsonView<Object> getObject(@RequestParam("id") Long id) { Object object = provider.getObject(id); return new JsonView(object); }
So it was working fine.
I have found some solution at How do you override the null serializer in Jackson 2.0? but unfortunatly it works only for fields in the POJOs.
Have you any ideas how in it can be handled?
Thanks in advance!
-
fashuser over 9 yearsDo you mean specify annotation under method signature, because this one provoke "Duplicate annotation @ResponseBody" compilation error?Thanks!
-
Phong Nguyen over 9 yearsNo I mean, you shouldn't put annotation after accessor and before datatype of a method. Use my way. Quality Scanner (such as SonarQube) will realize it's a major error and need to be refactor! I faced to it and get experiences. That's not "Duplicate annotation" compilation error. It will compile properly, but you should standardized your code.
-
fashuser over 9 yearsUnfortunatly any approach does not work in my case: 1) The first one continue return empty response as the following code are present in: Object body = responseEntity.getBody(); if (body != null) { writeWithMessageConverters(body, returnType, inputMessage, outputMessage); } else { // flush headers to the HttpServletResponse outputMessage.getBody(); }. So it's just preint null as priviues and avoid writeWithMessageConverters method.
-
Sotirios Delimanolis over 9 yearsHow is that an error? It might be code style opinion, but it's definitely not an error. And your answer doesn't answer the question.
-
Sotirios Delimanolis over 9 yearsYour second suggestion won't work, because the
null
will never reach theMappingJackson2HttpMessageConverter
, it will stop at theRequestResponseBodyMethodProcessor
. -
Phong Nguyen over 9 yearsYeap! it's not a syntax error, but if you apply quality scale. it's a major mistake and should be fixed! If you don't believe check SonarQube rule and find out why!
-
Sotirios Delimanolis over 9 yearsI don't know what you mean by quality scale and I don't know what you mean by major mistake. I understand that SonarQube doesn't like it as part of their code policy. In any case, your answer doesn't address the issue.