2

How to make following to work: - a spring bean that has a method that should be cached with @Cacheable annotation - another spring bean that creates keys for the cache (KeyCreatorBean).

So the code looks something like this.

@Inject
private KeyCreatorBean keyCreatorBean;

@Cacheable(value = "cacheName", key = "{@keyCreatorBean.createKey, #p0}")
@Override
public List<Examples> getExamples(ExampleId exampleId) {
  ...

However the above code doesn't work: it gives following exception:

Caused by: org.springframework.expression.spel.SpelEvaluationException: 
    EL1057E:(pos 2): No bean resolver registered in the context to resolve access to bean 'keyCreatorBean'
Juha Syrjälä
  • 33,425
  • 31
  • 131
  • 183
  • Try something like `#{keyCreatorBean.method}` instead of `@keyCreatorBean.method`.Just a random guess. – Ajinkya Jul 09 '12 at 16:21
  • Somewhat related question: http://stackoverflow.com/questions/5749730/bean-creation-using-spel-hibernate – Juha Syrjälä Jul 10 '12 at 06:44
  • You may try this: http://stackoverflow.com/a/8142249/799562 `` but need to implement `org.springframework.cache.interceptor.KeyGenerator`. – micfra Jul 10 '12 at 11:13
  • 1
    I made a ticket about this issue to SpringSource: https://jira.springsource.org/browse/SPR-9578 – Juha Syrjälä Jul 10 '12 at 12:52
  • Another related question: http://stackoverflow.com/q/5743565/1431 , here the problem is with Spring Security annotations, but the given workaround doesn't seem to work in my case. – Juha Syrjälä Jul 10 '12 at 12:54
  • As @biju-kunjummen has written down, the bean resolver is not set by the `EvaluationContext` used within the underlying classes. It would be possible but only by changing the implementation of `org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext` where the `EvaluationContext` is created. This may be a good hint to your JIRA ticket because that is the root cause. – micfra Jul 10 '12 at 18:01

2 Answers2

2

I checked the underlying cache resolution implementation, there doesn't appear to be a simple way to inject in a BeanResolver which is required for resolving the beans and evaluating expressions like @beanname.method.

So I would also recommend a somewhat hacky way along the lines of one which @micfra has recommended.

Along what he has said, have a KeyCreatorBean along these lines, but internally delegate it to the keycreatorBean that you registered in your application:

package pkg.beans;

import org.springframework.stereotype.Repository;

public class KeyCreatorBean  implements ApplicationContextAware{
    private static ApplicationContext aCtx;
    public void setApplicationContext(ApplicationContext aCtx){
        KeyCreatorBean.aCtx = aCtx;
    }


    public static Object createKey(Object target, Method method, Object... params) {
        //store the bean somewhere..showing it like this purely to demonstrate..
        return aCtx.getBean("keyCreatorBean").createKey(target, method, params);
    }

}
Biju Kunjummen
  • 49,138
  • 14
  • 112
  • 125
0

In the case you have a static class function, it will work like this

@Cacheable(value = "cacheName", key = "T(pkg.beans.KeyCreatorBean).createKey(#p0)")
@Override
public List<Examples> getExamples(ExampleId exampleId) {
  ...
}

with

package pkg.beans;

import org.springframework.stereotype.Repository;

public class KeyCreatorBean  {

    public static Object createKey(Object o) {
        return Integer.valueOf((o != null) ? o.hashCode() : 53);
    }

}
micfra
  • 2,780
  • 1
  • 23
  • 34
  • I need to use a spring bean, not a static factory method. – Juha Syrjälä Jul 10 '12 at 06:41
  • Working with `@keyCreatorBean.createKey(#p0)` failed as it does in your case. Maybe the context is not aware of the bean instance at cache annotation processing time? Some spring guru around? – micfra Jul 10 '12 at 08:56