5

Inspired by this answer I tried to do the following

@NoRepositoryBean
public interface CacheableRepository<T, ID extends Serializable>
    extends JpaRepository<T, ID>, JpaSpecificationExecutor<T>,       PagingAndSortingRepository<T, ID> {

    @Cacheable()
    T findOne(ID id);

    @Cacheable()
    List<T> findAll();

   @Cacheable()
   Page<T> findAll(Pageable pageable);

   @CacheEvict(allEntries = true)
   <S extends T> S save(S entity);

   @CacheEvict(allEntries = true)
   void delete(ID id);

}

Then use this interface to define the Used repository

 @CacheConfig(cacheNames={"uniqueCache"})
 public interface SomeObjectRepo extends    CacheableRepository<SomeObject, Long>  {

     @Cacheable(key = "someobject+#p0")
     List<SomeObject> findByType(Integer type);

    @Cacheable(key = "someobject+#p0")
    List<SomeObject> findByCategory(String field);

    @Cacheable(key="someobject+#p0.concat(#p1)")
    List<SomeObject> findByCategoryAndWizardType_id(String field,Integer id);

 }

Works:

The cache above work for findByType,findByCategory,findByCategoryAndWizardType_id

Does not work:

For all the cacheable methods defined at CacheableRepository. It seems that the CacheConfig annotation on SomeObjectRepo does not effect the CacheableRepository.

My question:

Why the annotation does not work? Is there a workaround to get this structure to work?

Thanks, Oak

Community
  • 1
  • 1
oak
  • 2,898
  • 2
  • 32
  • 65

2 Answers2

3

Yup, that's pretty much what Ollie and I found out when we tried to support that kind of scenario.

I would advise you to create an issue in the spring data project to request that feature.

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
  • Thanks for replying, My thoughts is that it is solvable via AOP. But i cannot think of the reason why it does not work. Maybe you can point it to me? – oak Oct 07 '15 at 08:55
  • My best guess is that the `@CacheConfig` annotation is not read on the proxy interface. It's something to fix in the core. If you want a generic Spring Data repository caching solution, please consider creating an issue there and we'll work on a standard solution. – Stephane Nicoll Oct 07 '15 at 09:26
  • Thanks for the info :) – oak Oct 07 '15 at 11:04
  • @oak Do you have any updates on this? Is it achievable after almost 8 years? – Toni Feb 27 '23 at 17:33
  • 1
    @birca123, left this project a while ago, so I do not have any new information regarding it, but if you have/know about a solution please write :-) – oak Feb 28 '23 at 08:34
0

By using CacheResolver shown below, the cache name can be determined based on the target repository's name, whose method was executed.

The configuration used to define the default CacheResolver:

@Configuration
@EnableCaching
@RequiredArgsConstructor
public class CacheConfig extends CachingConfigurerSupport {

  @Lazy private final CacheManager cacheManager;

  @Override
  public CacheResolver cacheResolver() {
    return new CustomCacheResolver(this.cacheManager);
  }

  public static class CustomCacheResolver extends SimpleCacheResolver {

    protected CustomCacheResolver(CacheManager cacheManager) {
      super(cacheManager);
    }

    @Override
    protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
      return List.of(context.getTarget().getClass().getInterfaces()[0].getSimpleName());
    }
  }
}

With this solution, there is no need to specify cache names, since all cacheable methods are cached under the SomeObjectRepo cache name.

Note: To cache class methods, additional logic should be added to getCacheNames, otherwise it would not work.

Toni
  • 3,296
  • 2
  • 13
  • 34