【问题标题】:Why doesn't reflection work when a class returns Lambdas为什么当类返回 Lambdas 时反射不起作用
【发布时间】:2015-03-03 21:29:01
【问题描述】:

我遇到了一个有点奇怪的行为。我使用注释来标记具有特定目的的某些类,然后我使用 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,反射将不起作用。

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

【问题讨论】:

  • 如果你return new Conumser&lt;Integer&gt; () { ... };可以吗?
  • 是的,如果 return new Consumer () {...} 它可以工作,那么两个类都会出现在反射中,但是当使用 lambda 表达式时它不会出现.
  • 我在一个简单的设置中使用了你的代码,clazzes 包含两个类FooBar 和BarClass。我使用了reflections 0.9.9 版。你的BaseClass.java 怎么样?
  • 我已经使用 BaseClass 更新了上面的示例 - 我使用了 0.9.9-RC1,但无法使其工作......
  • @Idlewood 用0.9.9-RC1 尝试了您的示例,并且可以确认它不起作用。因此,将版本从 0.9.9-RC1 更新为 0.9.9 即可。

标签: java reflection lambda annotations java-8


【解决方案1】:

从issues list 看来,这个库似乎还不适合 Java 8 功能。我认为您最好的选择是报告此问题并提供解决方案。

【讨论】:

  • 好像0.9.9版有解决这个问题的办法
【解决方案2】:

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

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,您要为其获取带注释的类。

【讨论】:

    猜你喜欢
    • 2013-01-23
    • 1970-01-01
    • 2012-01-21
    • 2012-08-23
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    相关资源
    最近更新 更多