3

我正在使用反射来查找具有特定注释的类。我的项目结构如下

一个 WAR 包:WEB-INF/classes/...packages.../ClassAnnoted1.class

战争中包含的一个 JAR 包,它有一个执行此代码的类:

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

CustomAnnotation 也存在于 JAR 包中。

设置大小是正确的(即,如果我的 WAR jar 中有 3 个带有注释的类,则设置大小返回为 3),但其中的所有元素都是 null 而不是 Class。我需要获取类并检查 JAR 类中的注释参数。

有人知道为什么会这样吗?

编辑:

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

也不起作用,在这种情况下,设置长度为零,而不是带有注释的类数。

编辑 2:好的,真正的问题是我将整个应用程序打包为 EAR,所以我有以下内容:

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

jar 包含在 EAR lib 文件夹中,而不是 WAR lib 文件夹中。所以jar类看不到war类,一旦我让WAR直接依赖于JAR,就像这样:

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

它开始工作了。但是最初的问题仍然存在,可能存在我希望将 Jar 类包含在 EAR 而不是 WAR 中的情况(例如,如果我有多个需要使用我的 jar 的战争)。

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 类以公开“类”属性。例如,Java 9 中可能不存在此属性,因此请注意。如果您正在与第三方编写的模块进行交互,这也可能存在一些安全问题。

于 2013-04-08T19:30:23.997 回答
1

我有一个类似的问题。你确定,你将注释类包含在你的类路径中吗?如果它们没有加载,它们会以某种方式被找到但不会真正返回,并且没有任何异常或任何东西

于 2013-04-08T12:25:39.390 回答
0

Reflections库给了我各种问题。现在我正在使用Guava库的反射部分:到目前为止,没有发生意外行为。无论如何,我认为问题的根源是 Java 类加载器是非常罕见的。也许尝试加载类CustomAnnotation.class之前在反射 API 中使用它。

于 2013-04-10T09:10:18.673 回答
0

您的代码应该可以在传统环境中运行。但是,在不同的环境中,例如 osgi,您会得到:

1) 不同协议的 url (bundle/vfs/...)

2)不同的类加载器。

在第一种情况下,您应该a)添加相关的 UrlType(参见Vfs中的 DefaultUrlTypes 示例),或b)使用不同的方法获取 url(参见 ClasspathHelper 中的其他方法并检查返回的 URL 列表)

在第二种情况下,您应该a)将 customClassLoader 传递给 Reflections 构造函数或 ConfigurationBuilder 以便进行解析,或者b)直接查询存储reflections.getStore().get(TypeAnnotationsScanner.class)

另见#8339845JbossIntegration

于 2013-04-14T11:03:19.490 回答