My plan is to write a annotation based caching framework which caches the return values of methods. When a method gets called the first time with a specific parameter, then the cache should store the methods return value. When the same method gets called a second time with the same parameter then the method should return the previously calculated result from the cache and not execute its code again. My annotations looks like this:
@Cached(cacheProvider = HashMapCacheProvider.class)
public Product getProduct(String productId){
// Scraping the product from a website ...
return product;
}
At the moment my little framework is working already fine. I'm using Javassist to create proxy objects of classes which are containing annotated methods. In order to create a new cached object I'm using this code:
public static <T> T newCachedInstance(Class<T> clazz)
throws InstantiationException, IllegalAccessException {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(clazz);
factory.setFilter(new MethodFilter() {
public boolean isHandled(Method m) {
// ignore finalize()
return !m.getName().equals("finalize");
}
});
Class<T> c = factory.createClass();
T proxy = c.newInstance();
((ProxyObject) proxy).setHandler(new CachedMethodHandler());
return proxy;
}
The problem is, that I can just create new cached objects by this method and not by the constructor of their classes. Therefore I'm searching a solution to attach already existing objects to the caching mechanism.
And here is my question: Is it possible to attach a proxy to an existing object? In my understanding this should not be possible without updating all existing references to this object.
My other approach is to use bytecode manipulation in order to manipulate the code of the annotated methods like this:
public class Hello {
public void say() {
System.out.println("Hello");
}
}
public class Test {
public static void main(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("Hello");
CtMethod m = cc.getDeclaredMethod("say");
m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
Class c = cc.toClass();
Hello h = (Hello)c.newInstance();
h.say();
}
}
Have you any other idea? What is the best practice to manipulate methods of existing objects?