当一个类返回Lambdas时,为什么反射不起作用

时间:2015-03-03 11:20:20

标签: java reflection lambda annotations java-8

我遇到了一种有些奇怪的行为。我使用注释来标记具有特定目的的某些类,然后我使用org.reflections库来查找具有特定注释的所有类。但是,当一个类实现一个返回lambda函数的方法时,反射将不再找到带注释的类。班级的签名没有变化。

注释示例:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
   String someValue();
}

使用注释(编辑 - 添加了BaseClass):

public class BaseClass {

    public Consumer<Integer> doSomething(){ return null;}
}


@MyAnnotation(someValue = "a")
public class FooBar extends BaseClass {

    @Override
    public Consumer<Integer> doSomething() {
        return null;
    }
}



@MyAnnotation(someValue = "bazbar")
public class BarClass extends BaseClass {

    @Override
    public  Consumer<Integer> doSomething(){
        return (x) -> {};
    }
}

查找注释

private static final Reflections reflections = new Reflections("com.mypackage");

Set<Class<?>> clazzes  = reflections.getTypesAnnotatedWith(MyAnnotation.class);

现在 - 设置'clazzes'只包含 1单个类,即FooBar类。如果我从BazBar类中删除lambda返回值也会显示,但只要该类中的一个方法返回一个lambda,反射就不会起作用。

我迷路了,有什么想法吗?

2 个答案:

答案 0 :(得分:2)

issues list看来,这个库似乎还不适合Java 8的功能。我认为你最好的办法是报告这个问题并提供修复。

答案 1 :(得分:1)

您可以在没有任何第三方代码的情况下执行查找,如下所示:

private static <T extends Annotation> Set<Class<?>> getAnnotated(
        Class<?> context, Class<T> anno) throws IOException, URISyntaxException {

    URI clURI = context.getResource(context.getSimpleName()+".class").toURI();
    if(!clURI.getScheme().equals("file")) try {
        FileSystems.getFileSystem(clURI);
    } catch(FileSystemNotFoundException ex) {
        FileSystems.newFileSystem(clURI, Collections.emptyMap());
    }
    String pkg=context.getPackage().getName();
    return Files.list(Paths.get(clURI).getParent())
        .map(p->p.getFileName().toString())
        .filter(s->s.endsWith(".class"))
        .map(s->s.substring(0, s.length()-6))
        .map(s-> { try {
            return context.getClassLoader().loadClass(pkg+'.'+s);
          } catch(ClassNotFoundException ex) { return null; } })
        .filter(c -> c!=null && c.isAnnotationPresent(anno))
        .collect(Collectors.toSet());
}

Path优于旧File的优势在于它对文件系统(存储)进行抽象,因此即使Class存储在一个文件系统中,也可用于列出包成员jar文件(或存在FileSystemProvider的任何其他类存储)。

您可以将其用作

Set<Class<?>> clazzes  = getAnnotated(context, MyAnnotation.class);

其中context是您要获取带注释类的包中的Class