将字段添加到使用Javassist创建的Proxy类

Fer*_*ndo 2 java bytecode-manipulation javassist

我正在使用Javassist ProxyFactory创建一个Proxy类,其代码如下:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(entity.getClass());
factory.setInterfaces(new Class[] { MyCustomInterface.class });
.....
Class clazz = factory.createClass();
Object result = clazz.newInstance();
Run Code Online (Sandbox Code Playgroud)

问题是我还需要在类中添加一个字段.但是,如果我这样做,CtClass proxy = ClassPool.getDefault().get(clazz.getName());他会嗤之以鼻NotFoundException

如何添加使用createClass创建的类的字段?有没有更好的方法来做我想做的事情?

pab*_*tes 6

这取决于您对我的评论的回复.

您确实可以使用MyCustomInterface和您的proxyClass一起在Java中创建一个mixin.但是你仍然必须从代理类转换MyCustomInterface为能够调用方法.

让我们开始吧.

创建代理

首先,您已经创建了代理服务器:

 // this is the code you've already posted
 ProxyFactory factory = new ProxyFactory();
 factory.setSuperclass(entity.getClass());
 factory.setInterfaces(new Class[] { MyCustomInterface.class });
Run Code Online (Sandbox Code Playgroud)

方法处理程序:做魔术

Javassist代理允许您添加MethodHandler.它基本上是一个常规Java代理中的InvocationHandler,这意味着它可以作为一个方法拦截器.

方法处理程序将是你的mixin!首先,使用您实际要添加到类中的自定义字段以及您已开始代理的实体对象创建一个新的MethodHandler:

  public class CustomMethodHandler implements MethodHandler {

    private MyEntity objectBeingProxied;
    private MyFieldType myCustomField;

    public CustomMethodHandler(MyEntity entity) {
       this.objectBeingProxied = entity;
    }

    // code here with the implementation of MyCustomInterface
    // handling the entity and your customField

    public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable {
          String methodName = method.getName();

          if(methodNameFromMyCustomInterface(methodName)) {
            // handle methodCall internally: 
            // you can either do it by reflection
            // or if needed if/then/else to dispatch
            // to the correct method (*) 
          }else {
             // it's just a method from entity let them
             // go. Notice we're using proceed not method!

             proceed.invoke(objectBeingProxied,args);
          }
    }
  }
Run Code Online (Sandbox Code Playgroud)

(*)请注意,即使我在注释中说在内部处理调用,您也可以在另一个不是方法处理程序的地方使用接口实现,只需从此处调用它即可.

让一切都在一起

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(entity.getClass());
factory.setInterfaces(new Class[] { MyCustomInterface.class });
Class cls = factory.createClass();

// bind your newly methodHandler to your proxy
((javassist.util.proxy.Proxy) cls).setHandler(new CustomMethodHandler(entity));
EntityClass proxyEntity = cls.newInstance();
Run Code Online (Sandbox Code Playgroud)

您现在应该能够做到((MyCustomInterface)proxyEntity).someMethodFromTheInterface()并让它由您处理CustomMethodHandler

加起来

  • 您可以使用javassist中的Proxy Factory创建代理
  • 您可以创建自己的MethodHandler类,该类可以接收您的代理实体和您要操作的字段
  • 将methodHandler绑定到代理,以便委派接口实现

请记住,这些方法并不完美,除非您首先创建代理,否则Entity类中的代码无法引用接口的缺点之一.

如果有什么不是很清楚,请发表评论,我会尽力澄清你.