【发布时间】:2011-11-29 22:06:14
【问题描述】:
我正在编写一个支持Frege 编程语言的eclipse 插件。 我使用IMP 元工具平台和 Eclipse Indigo (3.7)。运行时环境是 Java 1.7。
该插件使用与批处理编译器相同的代码进行令牌解析、语法分析等。但是,我注意到从 eclipse 插件运行时的不同行为,并将其追溯到以下读取先前的类文件的方法编译模块以获取以 java 注释形式存储在那里的元信息:
public static MD.Operator[] getOperators(ClassLoader loader, String pack)
throws ClassNotFoundException {
Class<?> cl = null;
cl = loader.loadClass(pack);
MD.FregePackage os = cl.getAnnotation(MD.FregePackage.class);
if (os == null) return null; // <-- no annotation present
return os.ops();
}
请注意,代码会创建自己的 URLClassLoader 实例,并作为参数传递。如果我没有正确设置类路径,getOperators 方法会正确抛出 ClassNotFoundException,因此我认为我可以确定它加载了类。
一条跟踪消息告诉我,类加载器是使用以下路径构建的(默认情况下只是类路径):
mkClassLoader:[C:\opt\eclipse\plugins\org.eclipse.equinox.launcher_1.2.0.v20110502.jar, X:\dev\frege\build]
因为不是由 frege 编译器创建的类文件通常不能有 MD.FregePackage 注释,这通常表明用户试图导入一个普通的 java 类,实际上我在插件中收到以下消息:
X:/dev/runtime-EclipseApplication/TestJFrege/src/Neu.fr:1: `frege.prelude.Base` is not a frege package
然而,从命令行我可以编译它就好了。我在此处包含此内容,以证明相关注释确实可以从同一位置加载:
X:\dev\frege>java -cp ./build frege.compiler.Main X:/dev/runtimeEclipseApplication/TestJFrege/src/Neu.fr
mkClassLoader: [./build]
running: javac -cp ./build -d . -encoding UTF-8 ./Neu.java
恢复事实:
- 当通过命令行界面调用编译器时,应该加载注释的代码可以正常工作。
- 应该加载注释的代码不知道它是从插件调用还是从命令行调用。事实上,该插件直到上周才出现,而命令行界面过去几个月都可以正常工作。
- 注释当然有
RetentionPolicy.RUNTIME,否则命令行编译也无法识别它们。但事实证明确实如此。
所以我能得出的唯一结论是Class.getAnnotation() 不知何故无法正常工作。这是非常不幸的,因为这有效地破坏了模块系统所需的基本功能。
如果这很重要:插件使用的 Frege 编译器代码本身是用 Frege 编写的,上面提到的 frege.prelude.Base 类是每个模块都需要的基本库,因此它必须已经已在激活插件时加载,当然使用不同的类加载器。
有人有类似经历吗?是否有可能解决这个问题以及如何解决?欢迎提出如何规避此问题的任何建议。
【问题讨论】:
-
你传入的类加载器作为父类加载器有什么?是已经加载了您的注释的类加载器吗?如果调用 getAnnotations() 而不是 getAnnotation(MD.FregePackage.class) 会发生什么?是非空的吗?
-
Is it the classloader which has already loaded your annotation?- 我希望如此,或者至少在批处理模式下似乎是这种情况,但在 eclipse 环境中可能会有所不同。一定要试试看! -
Eclipse 对类加载器做了各种奇怪的事情,以允许不同的包加载不同版本的类。您的类文字很可能与注释的类不匹配,只是因为它们是由不兼容的类加载器加载的。
标签: java eclipse reflection eclipse-plugin frege