Good Samartian
Good Samartian

Reputation: 113

Add a Constant Custom Prefix to Cache key when using Spring Caching Annotations

I am using Spring Cache abstraction based on annotations in my service.

I want to add a custom prefix to the key when added to the cache.

I created a constant and tried to add them to the methods as below.

private static final String CACHE_KEY_PREFIX="user";

    @Cacheable(value = "users", key = "{ CACHE_KEY_PREFIX,#userId }")
    @GetMapping("/{userId}")
    public User getUser(@PathVariable String userId) {
        LOG.info("Getting user with ID {}.", userId);
        return userRepository.findOne(Long.valueOf(userId));
    }


    @CacheEvict(value = "users",key="{ CACHE_KEY_PREFIX,#userId }" )
    @DeleteMapping
    public void deleteUserByID(@PathVariable Long userId) {
        LOG.info("deleting person with id {}", userId);
        userRepository.delete(userId);
    }   

But, I get the stacktrace as below.

2018-06-12 13:35:48.911 ERROR 8728 ---  [nio-8090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]     Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'hash(#)'] with root cause

org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'hash(#)'
    at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:129)
    at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:60)

Since I have multiple methods I do not want to hardcode the custom prefix in every method annotation.

Is there a way to add a custom prefix and avoid the exception I am seeing.

Upvotes: 2

Views: 5253

Answers (2)

user07
user07

Reputation: 415

One of the ways is to create a custom RedisCacheConfiguration bean. Note that a semicolon just a common delimiter between the parts of a key, it has no special purpose. A common prefix can be useful in a shared Redis instance to easily differentiate between the caches from different sources (example, from different microservices):

    @Configuration
    @EnableCaching
    public class MyCacheConfig {
    
       @Bean
       public RedisCacheConfiguration cacheConfiguration() {
                 return RedisCacheConfiguration.defaultCacheConfig()
                        .prefixCacheNameWith("myprefix:");
       }
    }

Upvotes: 0

Edvins
Edvins

Reputation: 426

To use a constant in the annotation, you could include it as a fixed String like this:

@Cacheable(value = "users", key = "{'" + CACHE_KEY_PREFIX + "', #userId}")
@GetMapping("/{userId}")
public User getUser(@PathVariable String userId) {
    LOG.info("Getting user with ID {}.", userId);
    return userRepository.findOne(Long.valueOf(userId));
}

In this case, the compiler will resolve the value of attribute key to {'user', #userId}.

Upvotes: 3

Related Questions