I have developed a REST end-point in Springboot that takes a String
ID and responds with a ModelAndView
. This end-point is marked with @Cacheable
annotation. Now there are two things that can happen at the given end-point.
Case 1: The request ID exists in the DB and yields a URL to which redirection needs to happen. In this case, response should be cached so that upon consecutive requests of the same ID, the result can be served from Cache
Case 2: The requested ID doesn’t exist in the DB and thus redirection should happen to a specific URL and no caching should be done in this scenario.
So below is my method
@GetMapping("{id}")
@Cacheable(value = "url-single", key = "#id", unless = "#result.view!="redirect:/notfound"")
public ModelAndView redirect(@PathVariable("id") String id, ServletRequest servletRequest,
ServletResponse servletResponse) {
HttpServletRequest request = HttpServletRequest.class.cast(servletRequest);
LOG.info("Redirection request from: {} for Short URL Key: {}", request.getRemoteAddr(), id);
try {
Optional<String> originalUrlOptional = urlManagerService.retrieveOriginalUrl(id);
if (originalUrlOptional.isPresent() && !StringUtils.isEmpty(originalUrlOptional.get())) {
LOG.info("Found Original URL: {} for Short URL Key: {}", originalUrlOptional.get(), id);
return new ModelAndView("redirect:https://" + originalUrlOptional.get());
}
} catch (NoSuchElementException e) {
LOG.error("Error while redirecting: {}", e.getMessage(), e);
}
return new ModelAndView("redirect:/notfound");
}
If I understand it correctly from here, the keyword unless
in @Cacheable
applies to the return type and in order to access any particular member variable of the return type object, we have to refer to it as #result.attributeName <comparison> <value>
.
So why isn’t anything being stored in my Redis cache? If I remove the unless
condition, everything gets stored. Is the condition not correct?
2
Answers
I found where I was going wrong after playing with the
unless
conditional keyword for awhile. The#result
inside the double quotes (") of theunless
keyword is literally the object to returned. What that means is that, you can call whatever method can be called on that object.The statement
"#result.view=="redirect:/notfound""
was failing because the object didn't expose any member variable calledview
. Using the expressionunless = "#result.getViewName().equals("redirect:/notfound")"
actually did the trick because there was a methodgetViewName()
on the object that returned String and callingequals()
on it did the actual comparison.I guess I got stuck here because I wasn't not familiar with Spring Expression Language or SpEL
I have been looking at your unless statement:
so this means that it WONT be cached if the result.view IS NOT redirect:/notfound.
My assumption is that you want to cache it, except when redirect:/notfound.
There is a “double negative” here.
So you probably should use:
(so use ‘==’ instead of ‘!=’)
Let me know if this works!