我有第三方API调用,它返回以下对象:
public class A {
protected void common() {
System.out.println("common is called in A");
}
public void test1() {
common();
System.out.println("test1 is called in A");
}
public void test2() {
common();
System.out.println("test2 is called in A");
}
}
但是我想像下面的ModifiedA节目一样修改它的行为:
public class ModifiedA extends A {
@Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
所以我想做的是:
A a = 3rdPartyAPI_call();
//
// Now I'd like to get a ModifiedA which has changed common() behavior.
//
如何使用javassist / CGLIB来实现这个目标?
一种简单的方法可能就是这样:
public class ModifiedA extends A {
private A a;
public ModifiedA(final A a) {
this.a = a;
}
//
// Override every public method in A
//
@Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
但由于A的定义来自第三方并且非常复杂并且可能会发生变化,所以我想使用代理来实现这一目标吗?
感谢您的评论。
答案 0 :(得分:2)
您可以使用CGLib实现委托者模式,而无需覆盖所有方法。根据样式,有几种不同的方法可以实现这一点,但这里有一个类似于你的例子。
您可以使用cglib Enhancer
包装实例:
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object returnValue = proxy.invoke(original, args);
if (method.getName().equals("common")) {
System.out.println("common is called");
}
return returnValue;
}
});
return (T) enhancer.create();
}
答案 1 :(得分:0)
eclps帖子将满足您的要求并且有效。我想为eclps代码添加更多代码。
添加为常用方法提供索引零的过滤器,并将所有方法保留为One。 MethodInterceptor回调只会拦截常用方法,并且所有方法都使用NoOp intercetor(它将调用超类apis)。这样每次方法调用都不会进行过滤。
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
if (method.getName().equals("common")) {
return 0;
}
return 1;
}
});
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// only common method will intercept this call back.
return proxy.invoke(this, args);
}
}, NoOp.INSTANCE});
return (T) enhancer.create();
}