3

リフレクションを使用して、特定の注釈を持つクラスを見つけています。私のプロジェクト構造は次のとおりです

1 つの WAR パッケージ: WEB-INF/classes/...packages.../ClassAnnoted1.class

次のコードを実行するクラスを持つ war に含まれる 1 つの JAR パッケージ:

Reflections reflections= new Reflections(ClasspathHelper.forWebInfClasses(servletContext))
Set set= reflections.getTypesAnnotatedWith(CustomAnnotation.class)

CustomAnnotation も JAR パッケージに含まれています。

セットのサイズは正しいです (つまり、WAR の jar にアノテーションを持つ 3 つのクラスがある場合、セットのサイズは 3 に戻ります) が、その中のすべての要素は Class ではなく null です。クラスを取得し、JAR のクラス内の注釈パラメーターを確認する必要があります。

なぜこれが起こっているのか誰にも分かりますか?

編集:

Reflections reflections= new Reflections("com.my.customAnnotededClasses"); //package that my annoted class is in
Set set= reflections.getTypesAnnotatedWith(CustomAnnotation.class);

また、機能しません。この場合、セットの長さは、注釈付きのクラスの数ではなくゼロです。

EDIT 2:わかりました、本当の問題は、アプリケーション全体をEARとしてパッケージ化していたため、次のようになったことです:

EAR
----> WAR
----> JAR

jar は、WAR lib フォルダーではなく、EAR lib フォルダーに含まれていました。したがって、jar クラスは war クラスを表示できませんでした。WAR を次のように JAR に直接依存させると、次のようになります。

EAR
----> WAR
---------> JAR

それは働き始めました。しかし、元の質問はまだ残っています。WAR の代わりに EAR に Jar クラスを含めたい状況があるかもしれません (たとえば、jar を使用する必要がある複数の war がある場合)。

4

4 に答える 4

2

反射ライブラリを使用してそれを行うことはできないと思います。だから私は手でそれをやった:

public static List<Class<?>> getClassesAnnotatedWith(Class annotation, ServletContext servletContext) {
    List<Class<?>> webClasses, jarClasses;
    webClasses= getClassesAnnotedWithFromClassLoader(annotation, servletContext.getClassLoader());
    jarClasses= getClassesAnnotedWithFromClassLoader(annotation, Thread.currentThread().getContextClassLoader());
    for (Class<?> jarClass : jarClasses) {
        Class<?> elementToAdd= null;
        for (Class<?> webClass : webClasses) {
            if ( ! jarClass.getName().equals(webClass.getName())) {
                elementToAdd= jarClass;
            }
        }
        if(elementToAdd != null) {
            webClasses.add(elementToAdd);
        }
    }
    return webClasses;
}


 private static List<Class<?>> getClassesAnnotedWithFromClassLoader(Class annotation, ClassLoader classLoader) {
        List<Class<?>> classes= new ArrayList<Class<?>>();
        Class<?> classLoaderClass= classLoader.getClass();
        while (! classLoaderClass.getName().equals("java.lang.ClassLoader")) {
            classLoaderClass= classLoaderClass.getSuperclass();
        }
        try {
            Field fldClasses= classLoaderClass.getDeclaredField("classes");
            fldClasses.setAccessible(true);
            Vector<Class<?>> classesVector= (Vector<Class<?>>) fldClasses.get(classLoader);
            for (Class c : classesVector) {
                if (c.isAnnotationPresent(annotation)) {
                    classes.add(c);
                }
            }
        } catch (Exception e) { }
        return classes;
    }

ServletContext オブジェクトを介して WAR パッケージから ClassLoader を取得します。クラスが WAR と JAR の両方でアノテーションと同じ名前で定義されている場合の保護もあります (おそらく、パッケージも同じかどうかを確認する必要があります)。

おそらく、このコードを自分のプロジェクトで使用するべきではないことに注意してください (おそらくデバッグ目的のみ)。ClassLoader クラスを反映して、"classes" プロパティを public にする必要があります。このプロパティは、たとえば Java 9 には存在しない可能性があるため、注意してください。また、サード パーティによって作成されたモジュールを操作している場合、セキュリティ上の問題が発生する可能性があります。

于 2013-04-08T19:30:23.997 に答える
1

私は同様の問題を抱えていました。注釈クラスをクラスパスに含めてよろしいですか? それらがロードされていない場合、それらは何らかの形で見つかりますが、実際には返されず、例外も何もありません

于 2013-04-08T12:25:39.390 に答える
0

コードは従来の環境で動作するはずです。ただし、osgi などのさまざまな環境では、次のようになります。

1) プロトコルが異なる URL (bundle/vfs/...)

2) 異なるクラスローダー。

最初のケースでは、a)関連する UrlType を追加する (例については Vfs の DefaultUrlTypes を参照)、またはb)別のメソッドを使用して URL を取得する (ClasspathHelper の他のメソッドを参照し、返された URL リストを調べる) 必要があります。

2 番目のケースでは、a )解決が行われるように customClassLoader を Reflections コンストラクターまたは ConfigurationBuilder に渡すか、b)ストアに直接クエリを実行する必要があります。reflections.getStore().get(TypeAnnotationsScanner.class)

#8339845JbossIntegrationも参照

于 2013-04-14T11:03:19.490 に答える