返回的反射使用null元素设置

时间:2013-04-05 19:30:23

标签: java reflection google-reflections

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

一个WAR套餐: WEB-INF /类/ ...包... / ClassAnnoted1.class

war包含的一个JAR包,它包含一个执行此代码的类:

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

CustomAnnotation也出现在JAR包中。

设置大小是正确的(即如果我的WAR中有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

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

4 个答案:

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

答案 1 :(得分:1)

我有一个类似的problem。你确定,你在你的类路径中包含了注释类吗?如果他们没有加载,他们将以某种方式被发现,但没有真正返回,没有任何例外或任何

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您的代码应该适用于传统环境。 但是,在不同的环境中,例如osgi,你得到:

1)具有不同协议的URL(bundle / vfs /...)

2)不同的类加载器。

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

在第二种情况下,您应该 a)将customClassLoader传递给Reflections构造函数或ConfigurationBuilder,以便进行解析,或者 b)直接查询商店{{1 }}

另见#8339845JbossIntegration