2

ある日以来、私はこの問題で立ち往生しています。しかし、最初に説明したいと思います。

EE7 と Glassfish4 を使用して Java で RESTful API を構築しています。認証と承認は自分で作成する必要があります (学生プロジェクト)。そこで、@AccesRight と @Roles に独自のアノテーションを追加するというアイデアが生まれました。モデルの各 set および get メソッド (宣言されている場合) のメタデータを解釈した後、ユーザーがこれを表示する権利を持っていない場合は、実行時に @XmlTransient アノテーションを設定する必要があります。要するに、モデル属性で異なるアクセスを許可します。

_model-class-methods (メソッド シグネチャを参照) からメソッド アノテーションを変更しようとしましたが、「.toClass()」を実行すると失敗します。これは、WebAppClassLoader に既にクラスが読み込まれているためです (エントリが重複しています)。そこで、特定のモデル (_model.getClass().getName() + transactionToken) の別の名前でコピーを作成することにしました。大きな問題: このコピーを元のモデルにキャストできなくなりました (ClassCastException が発生します)。クラスとコピークラスは同じクラスローダーに格納されます。

そこで、すべてのモデルに格納されている「loadModelByEntity(UserModel _model)」などのメソッドを呼び出すことを検討しました。問題は次のとおりです。コピー クラスの .toClass() を実行した後、メソッド シグネチャは次のようになります。

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

1 に答える 1