简体   繁体   English

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

[英]Why doesn't reflection work when a class returns Lambdas

I have encountered a somewhat strange behaviour. 我遇到了一种有点奇怪的行为。 I use annotations to mark certain classes with a particular purpose, and then I use org.reflections library to find all the classes with the particular annotation. 我使用注释来标记具有特定目的的某些类,然后我使用org.reflections库来查找具有特定注释的所有类。 However when a class implements a method that returns a lambda function, the reflection won't find the annotated class anymore. 但是,当一个类实现一个返回lambda函数的方法时,反射将不再找到带注释的类。 The signature of the class is unchanged. 班级的签名没有变化。

Example of annotation: 注释示例:

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

Using the annotation (EDIT - added the BaseClass): 使用注释(编辑 - 添加了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) -> {};
    }
}

Finding the annotations 找到注释

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

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

Now - the set 'clazzes' only contains 1 single class , the FooBar class. 现在 - 集合'clazzes'只包含1个单独的类 ,即FooBar类。 If I remove the lambda return value from the BazBar class that one too shows up, but as soon as one method in the class returns a lambda the reflection wont work. 如果我从BazBar类中删除lambda返回值,那么也会显示一个,但只要该类中的一个方法返回一个lambda,反射就不会起作用。

I'm lost, any ideas? 我迷路了,有什么想法吗?

From the issues list it seems that this library isn't fit for Java 8 features yet. 问题列表看,这个库似乎还不适合Java 8功能。 I think your best bet is reporting this problem and maybe provide a fix. 我认为你最好的办法是报告这个问题并提供修复。

You may perform the lookup without any third-party code as follows: 您可以在没有任何第三方代码的情况下执行查找,如下所示:

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());
}

The advantage of Path over good old File is that it abstracts over the filesystem (storage) and thus can be used to list package members even if the Class is stored in a jar file (or any other kind of class storage for which a FileSystemProvider exists). Path优于旧File的优势在于它对文件系统(存储)进行抽象,因此即使Class存储在jar文件(或存在FileSystemProvider任何其他类存储中),也可用于列出包成员)。

You may use it as 你可以用它作为

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

where context is a Class within the package for which you want to get a annotated classes. 其中context是一个Class ,而您想获得一个注解类的包内。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM