ある日以来、私はこの問題で立ち往生しています。しかし、最初に説明したいと思います。
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();
}