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

时间:2013-12-08 22:53:10

标签: java javassist bytecode-manipulation

我正在使用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();

问题是我还需要在课程中添加一个字段。但是,如果我CtClass proxy = ClassPool.getDefault().get(clazz.getName());,则会发出NotFoundException

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

1 个答案:

答案 0 :(得分: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 });

方法处理程序:做魔术

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);
          }
    }
  }

(*)请注意,即使我在评论中说要在内部处理调用,你也可以将接口实现放在另一个不是方法处理程序的地方,只需从这里调用它。

将所有内容放在一起

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();

您现在应该可以执行((MyCustomInterface)proxyEntity).someMethodFromTheInterface()并由CustomMethodHandler

处理

总结

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

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

如果您不清楚任何事情,请发表评论,我会尽力澄清您。