0

I encountered a strange behaviour while using @Cacheable annotation in Spring. I have a method marked as @Cacheable and that returns Map:

//dao layer @Cacheable(value = "Cache1") public Map<String, String> getNamesByDateAndCurrency(LocalDate date, String currency) { // Returns some map } 

I call this method from the following method and change the map using the retainAll() method:

//service layer @Autowired private DaoImpl dao; ... @Cacheable( value = "Cache2") public List<Integer> getUUIDs(Integer requestNumber, Set<String> set) { //some code.. Map<String, String> names = dao.getNamesByDateAndCurrency(params..); names.keySet().retainAll(set); //some other code, no any changes of map in further } 

dao.getNamesByDateAndCurrency(params..) expression returns, as expected, the cached data if I call this method a second time with the same parameters.

The problem is that the getNamesByDateAndCurrency method is caching the data changed after performing the retainAll method.

My question is why an external action (retainAll) method affects the cached response? Why hasn't it returned original data from getNamesByDateAndCurrency method?

Thanks in advance!

4
  • Because it is basically the same object reference. It doesn't give you a copy of the object Commented Feb 5, 2018 at 11:50
  • 1
    Possible duplicate of Caching of nested cacheable operation via SpringCache Commented Feb 5, 2018 at 11:51
  • @RomanVottner this isn't a duplicate of that question Commented Feb 5, 2018 at 12:07
  • @pvpkiran I get it but why the data updated in cache by external operation (retainAll) on the object reference? Why data didn't cached while call getNamesByDateAndCurrency method and then no any cache updates ? Commented Feb 5, 2018 at 12:10

1 Answer 1

1

Spring cache stores the result in the cache by reference. Then, the caching framework used (Ehcache in your case I think) will store the result according to its configuration. Most frameworks will store it by reference by default because it is much faster.

You have 2 solutions:

  1. Code in an immutable way. So when receiving the map, instead of modifying it in place, just create a copy. You can make sure of it by wrapping the result in a Collections.unmodifiableMap
  2. Tell Ehcache to store by value. This is a bit more involved because you need to be able to copy the value. But it will work transparently

Note that whether you are storing data on the heap, on disks or clustered, it would work as expected by default. Because all these options require to copy the key and the value. Only on-heap has a "by reference" storage optimization.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.