2013-12-08 32 views
2

我創建使用了Javassist ProxyFactory裏用下面的代碼的代理類創建的代理類:添加字段,用Javassist

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創建的類?有沒有更好的方法來做我想做的事情?

+0

它似乎並不打算操縱這些代理類。不會有任何代碼使用該字段。如果你想要一個非平凡的類,使用一個類工廠。 – Holger

+0

該字段是否會被MyCustomInterface中暴露的方法使用? – pabrantes

+0

準確地說,該字段將被MyCustomInterface中的方法使用。 AFAIK java不允許在接口中聲明實例字段。 – Fernando

回答

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,這意味着它可以作爲一個方法攔截器。

方法處理程序將是你的混合!首先,你創建你真的想添加到類,你已經開始代理實體對象沿自定義字段新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
  • 您可以創建自己的MethodHandler類,該類可以接收您的代理實體,要操作
  • 領域你methodHandler綁定到你的代理,所以你可以委託接口實現

請記住,這些方法是不完美的,是短缺憾的一個代碼除非您首先創建代理,否則實體類不能引用該接口。

如果有什麼不是很清楚,只是評論,我會盡我所能來澄清你。

+0

非常感謝!這是一個好主意....只是要提一下,MethodHandler是一個接口,而不是一個類,所以我必須實現MethodHandler(不擴展) – Fernando

+0

嗨費爾南多,很高興我能幫上忙!對不起,關於MethodHandler的不匹配,我寫了它,沒有編譯器幫助;-)我會編輯帖子來糾正這個細節。 – pabrantes

+0

如果你能寫的所有的東西只是出於你的頭,你是天才(但願不是一個瘋狂的一個) – Fernando