2013-07-02 119 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);