Marged Marged - 4 months ago 29
Java Question

How to have spring cache store the ResponseBody and not the intermediary object

I use spring cache with this method which returns the queried value as JSON:

public HugeValue getHugeValueFromSlowFoo( @RequestParam(value = "id", defaultValue = "") String id ) {
return Foo.getById( id );

This works fine and the HugeValue-object is stored in the cache (Hazelcast in this case). I want to further improve this because the time taken to create JSON from the HugeValue is quite high.
Can I tell spring cache to cache the JSON-ified version of my object ?

I use Jackson with Spring Boot 1.2 and Spring 4.1


Without really knowing your exact use case (I'm not yet allowed to add comments for asking unfortunately), I try to give a short summary on the ideas I have in mind. They all assume that you use Jackson for json mapping and at least Spring 3.1.

There is no enableResponseBodyCaching feature in SpringMVC as far as I know.

First alternative: Use http caching because it seems like you really want to cache the whole http response. Spring offers a straight forward way of global configuration:

    <bean id="webContentInterceptor"
        <property name="cacheSeconds" value="0"/>
        <property name="useExpiresHeader" value="true"/>
        <property name="useCacheControlHeader" value="true"/>
        <property name="useCacheControlNoStore" value="true"/>

If you wish to control this per Controller, inherit from Spring AbstractController and set cacheSeconds property according to javaDoc.

True power of http caching comes with a http proxy in front of your server of course.

Second idea: Implement your own subclass of MappingJackson2HttpMessageConverter. In writeInternal() you could add some logic which accesses a cache to retrieve an already mapped version instead of mapping the input object. This approach means that you will hit your services in order to retrieve the java object behind the Json stream. If this is fine for you because there is also caching at some point, this approach is worth a try imho.

Third idea: Do the json mapping on your own in a dedicated wrapper service which provides raw json strings/streams. You can easily inject the Jackson mapper (class name ObjectMapper) and gain full control over the mapping. Annotating this service then allows you to cache the results. In your Controller you only provide a ResponseEntity of the according type you whish to use (String or some stream). This would even prevent deeper service access if there is a cached result present.

Edit: Probably the MappingJackson2JsonView could also get handy. To be honest, I never worked with it before so I can't really say something about its usage.

Hope that helps and/or gives inspiration! Cheers