Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Ajax @ResponseBody with null returned values

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 of null.

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!

like image 797
fashuser Avatar asked Sep 03 '14 17:09

fashuser


2 Answers

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 HandlerMethodReturnValueHandlers. 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.

like image 192
Sotirios Delimanolis Avatar answered Oct 04 '22 02:10

Sotirios Delimanolis


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.

like image 28
Gerardo Avatar answered Oct 04 '22 03:10

Gerardo