Reputation: 1584
I'm trying to do a simple cache task. I have a Holiday
object, which has two fields: referenceDate
and isHoliday
. I then have a method that will make a HTTP request to a rest api in order to check if a date is a holiday or not. What I want to achieve is: if the current cached Holiday
object has the same referenceDate as the one passed as a parameter, return the cached value. I have a specific class to perform that check. Here is the code:
Holiday class
@AllArgsConstructor
@Getter
public class Holiday {
public LocalDate referenceDate;
public boolean isHoliday;
}
CacheService class
@DomainService
public class CacheService {
@Autowired
private CacheManager cacheManager;
public boolean isReferenceDateCached(final LocalDate referenceDate){
final Holiday holiday = (Holiday) cacheManager.getCache("holiday").get("holidaycheck");
return(holiday.getReferenceDate().equals(referenceDate));
}
}
HolidatInfraService class
@AllArgsConstructor
@Service
@Slf4j
public class HolidayInfraService {
@Autowired
private final CacheService cacheService;
@Cacheable(value = "holiday", key = "holidaycheck", condition = "#cacheService.isReferenceDateCached(#holidayDateToCheck)")
public Holiday isHoliday(final LocalDate holidayDateToCheck) {
//some code to call a rest api
}
}
And this is the error I get from my unit test when I try to holidayInfraService.isHoliday(someDate)
:
org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method isReferenceDateCached(java.time.LocalDate) on null context object
From this exception message seems pretty obvious that cacheService
is null. However, when I debbuged the code and got inside isHoliday
, cacheService
is not null. Maybe it hasn't been autowired yet by the time the annotation runs? It is also the first time I'm working with SPEL, so maybe something there too. If in fact cacheService
is not autowired yet, is there a workaround?
Upvotes: 4
Views: 18271
Reputation: 1099
Try
@Cacheable(value = "holiday", key = "holidaycheck", condition = "#{cacheService.isReferenceDateCached(#holidayDateToCheck)}")
public Holiday isHoliday(final LocalDate holidayDateToCheck) {
//some code to call a rest api
}
Upvotes: -1
Reputation: 86
Because you are using the @Cacheable(...)
annotation, Spring will evaluate that SpEL expression with the context class MethodBasedEvaluationContext
. This will set the root object to be a CacheExpressionRootObject
, and property lookups will be performed using that root object.
Since you are trying to refer to a property on a bean, the easiest solution would be to directly reference that bean in the SpEL expression. This is done with an @
(e.g. @myBeanName
). Spring will then look for a bean with that name in the ApplicationContext
. Remember that a bean defined without an explicit name will be named using the lower camel-came of the class name. For example, a class with the name MyBeanName
will have a bean name of myBeanName
.
Try changing your condition=
block to
@Cacheable(value = "holiday", key = "holidaycheck", condition = "@cacheService.isReferenceDateCached(#holidayDateToCheck)")
public Holiday isHoliday(final LocalDate holidayDateToCheck) {
//some code to call a rest api
}
Upvotes: 4
Reputation: 2422
In SpEL's MethodBasedEvaluationContext
to access method variable, you need to use #
, but no #
is needed for class variables. Property lookup will automatically find getter for the property without #
symbol. So, your SpEL should be
cacheService.isReferenceDateCached(#holidayDateToCheck)
And if this SpEL won't work, try creating getter method for cacheService
.
Upvotes: 0