2013-07-02 115 views
2

因爲有一天我被困在這個問題中。但首先我想描述一下,爲什麼我要按照所示方式行事:在運行時添加@XmlTransient註釋(結合自己的註釋)

我們正在使用EE7和Glassfish4在Java中構建一個RESTful API。認證和授權必須由我們自己構建(學生項目)。所以這個想法是爲@AccesRight和@Roles添加我們自己的註釋。在解釋每個集合上的元數據並獲得我們模型的方法(如果聲明)後,應在運行時設置@XmlTransient註釋,當用戶無權查看時。簡而言之:在模型屬性中授予不同的訪問權限。我試圖從_model-class-methods(請參閱方法簽名)修改方法註釋,但是當我運行「.toClass()」時,它失敗了,因爲WebAppClassLoader已經加載了一個類(重複條目)。所以我決定使用給定模型的另一個名稱(_model.getClass()。getName()+ transactionToken)創建副本。最大的問題是:我無法將這個副本轉換爲原始模型(我得到ClassCastException)。類和copyclass存儲在同一個類加載器中。

所以我認爲要調用像「loadModelByEntity(UserModel _model)」存儲在所有模型中。問題是:在運行.toClass()我的副本類後的方法簽名,現在看起來如下:loadModelByEntity(UserModel020a8e6bb07c65da3e9095368db34e843c0b0d1e _model)

了Javassist正在改變類中的所有數據類型。

有什麼辦法來防止這種情況發生,或者用我的複製模型填充數據嗎?有什麼方法可以投射我的複製模型?

非常感謝! 菲爾

//my annotation interface 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.TYPE, ElementType.METHOD}) 
public @interface AccessRight 
{ 
    String name() default ""; 
    Role[] roles() default {}; 
    boolean self() default true; 
    boolean friends() default true; 
} 




//my method where i analyse the annotation (and perhaps set a new one) 
public Object filter(Object _model, String _transactionToken) throws Exception 
{ 

    String className = _model.getClass().getName() + transactionToken; 
    ClassPool pool = ClassPool.getDefault();  
    CtClass copyClass = pool.getOrNull(className); 

    if(copyClass != null) 
    { 
     Class filterModel  = copyClass.getClass().getClassLoader().loadClass(className); 
     Object filterInstance = filterModel.newInstance(); 

     filterInstance.getClass().getDeclaredMethod("loadByEntity", _model.getClass()).invoke(filterInstance, _model); 

     return filterInstance; 
    } 

    pool.insertClassPath(new ClassClassPath(_model.getClass()));   

    pool.makeClass(className); 
    copyClass = pool.getAndRename(_model.getClass().getName(), className); 

    ClassFile copyClassFile = copyClass.getClassFile(); 
    ConstPool constPool = copyClassFile.getConstPool(); 

    AnnotationsAttribute attribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); 
    Annotation   annotation = attribute.getAnnotation("javax.xml.bind.annotation.XmlTransient"); 

    if(annotation == null) 
    { 
     attribute.addAnnotation(new Annotation("javax.xml.bind.annotation.XmlTransient", constPool)); 
    } 

    for(CtMethod method : copyClass.getDeclaredMethods()) 
    { 
     if(method.hasAnnotation(AccessRight.class)) 
     { 
      AccessRight arAnnotation = (AccessRight)method.getAnnotation(AccessRight.class); 

      if(!checkAccess(arAnnotation.name(), arAnnotation.roles(), arAnnotation.friends(), arAnnotation.self())) 
      { 
       method.getMethodInfo().addAttribute(attribute); 
      } 
     } 
    } 

    return copyClass.toClass().newInstance(); 
} 


//my consideration to fill the copy model (but it doesn`t work, like i described) 
public void loadByEntity(UserModel _model) 
{  
    this.m_id    = _model.getId(); 
    this.m_firstname  = _model.getFirstname(); 
    this.m_lastname   = _model.getLastname(); 
    this.m_username   = _model.getUsername(); 
    this.m_birthday   = _model.getBirthday(); 
    this.m_email   = _model.getEmail(); 
    this.m_password   = _model.getPassword(); 
    this.m_roleId   = _model.getRoleId(); 
    this.m_timestampCreated = _model.getTimestampCreated(); 
    this.m_accessRightList = _model.getAccesRightList(); 
} 
+0

我發現vor鑄造(但非常sc))的一種可能的方式是設置原始模型的超類。但是,我的所有方法都是重複的。他的問題很大:我的方法loadByEntity()完全是另一個,因爲方法簽名看起來像loadByEntity(UserModel020a8e6bb07c65da3e9095368db34e843c0b0d1e _model) –

回答

2

我刪除上運行的方法「loadByEntity」(這是Settings.ENTITY_LOAD_METHODNAME)在副本中類解決了這個問題。然後我用自定義的Signature和原始類的javassist codeAttribute將該方法讀入了副本類。此外,我還將原始類添加爲投射問題的超類。所以我的簽名看起來不錯,我可以投射到原來的模特身上。這些方法現在全部被覆蓋,因爲簽名是相同的。

String className = _model.getClass().getName() + _transactionToken + Helper.getUnixTimestamp()/Math.random(); 

    ClassPool pool = ClassPool.getDefault();  
    pool.insertClassPath(new ClassClassPath(_model.getClass())); 

    CtClass copyClass  = pool.getAndRename(_model.getClass().getName(),className); 
    CtClass originalClass = pool.get(_model.getClass().getName()); 
    ClassFile copyClassFile = copyClass.getClassFile(); 
    ConstPool constPool  = copyClassFile.getConstPool(); 

    copyClass.setSuperclass(pool.get(_model.getClass().getName())); 
    copyClass.removeMethod(copyClass.getDeclaredMethod(Settings.ENTITY_LOAD_METHODNAME)); 

    //creates a new method without codeattribute BUT(!) it is abstract 
    CtMethod newLoadMethod = new CtMethod(CtClass.voidType, Settings.ENTITY_LOAD_METHODNAME, new CtClass[] {originalClass}, copyClass); 
    CtMethod oldLoadMethod = originalClass.getDeclaredMethod(Settings.ENTITY_LOAD_METHODNAME); 

    //set modifier to NOT abstract 
    newLoadMethod.setModifiers(newLoadMethod.getModifiers() & ~Modifier.ABSTRACT); 
    //set the old code attribute 
    newLoadMethod.getMethodInfo().setCodeAttribute(oldLoadMethod.getMethodInfo().getCodeAttribute()); 
    copyClass.addMethod(newLoadMethod);