javaspring-bootcaching

Spring Boot @Cacheable stopped working after I moved method to the same class


I am doing a bit of refactoring in my project and I am facing really weird problem.

I have this service class which is taking care of fetching and parsing data from API. Before refactoring, I had special class only for this cache method and now I moved it here but it suddenly stop working. (When I set a breakpoint inside cache method, it is summoned every time I call this method, before, it was summoned only for the first time, than it returns value from cache)

Here is my service class:

    private static final String TRANSPORT_LOCATIONS = "transportLocations";
    private static final String CACHE_MANAGER = "cacheManager";
    private static final String ROOT_METHOD_NAME = "#root.methodName";
    private static final int FALLBACK_TIMEOUT = 1000;

    ...

    @Override
    public List<TransportLocation> fetchAllTransportsLocations() throws Exception {
        final var bodyStructure = createTransportLocationBody();
        final String body = buildBody(bodyStructure);
        final String url = transportLocationApiUrl + getCurrentTimeStamp();
        final HttpResponse<String> response = getTransportsLocations(url, body);
        if (isResponseBad(response.statusCode())) {
            LOG.error(GET_TRANSPORT_LOCATION_BAD_REQUEST_ERROR_MESSAGE);
            return createEmptyList();
        }
        return mapTransportsLocationsResponse(response.body());
    }

    @Cacheable(value = TRANSPORT_LOCATIONS, cacheManager = CACHE_MANAGER, key = ROOT_METHOD_NAME, sync = true)
    private HttpResponse<String> getTransportsLocations(final String url, final String body) throws Exception {
        HttpResponse<String> response = httpService.sendPostRequestWithBody(url, body);
        if (isResponseBad(response.statusCode())) {
            response = handleBadRequest(url, body);
        }
        return response;
    }

    private HttpResponse<String> handleBadRequest(final String url, final String body) throws Exception {
        LOG.error(GET_TRANSPORT_LOCATION_CACHE_BAD_REQUEST_ERROR_MESSAGE);
        Thread.sleep(FALLBACK_TIMEOUT);
        return httpService.sendPostRequestWithBody(url, body);
    }

Here is my cacheConfig class

    @Bean
    public net.sf.ehcache.CacheManager ehCacheManager() {
        final CacheConfiguration transportLocationCache = new CacheConfiguration();
        final net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();

        transportLocationCache.setName(CACHE_NAME);
        transportLocationCache.setMaxEntriesLocalHeap(ENTRIES_LOCAL_HEAP);
        transportLocationCache.setMemoryStoreEvictionPolicy(LRU);
        transportLocationCache.setTimeToLiveSeconds(TTL_SECONDS);
        config.addCache(transportLocationCache);

        return net.sf.ehcache.CacheManager.newInstance(config);
    }

    @Bean
    @Override
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheManager());
    }

Do you have any idea, what could be wrong?

Thank you very much.


Solution

  • When having a look into Cacheable source, doc says:

    Annotation indicating that the result of invoking a method (or all methods in a class) 
    can be cached.
    Each time an advised method is invoked, caching behavior will be applied, checking 
    whether the method has been already invoked for the given arguments. 
    

    The most relevant part of this snippet for this question, is advised method. In order to make AOP work, you'll need to organize the code as you did before.

    Explanation of why private methods cannot be used with AOP:

    Because private methods are not inherited by subclasses, i.e. there is no way to 
    intercept a private method and then delegate to it because the subclass cannot even 
    call that method. This is a normal Java limitation and has nothing to do with AOP specifically.
    

    https://stackoverflow.com/a/59961404/14072498

    The link provided by Pablo explains why calling method cannot reside in same class as method annotated with Cacheable.