我面临的问题是“普通”Java、Equinox 以及两者之间的通信的组合。我已经阅读了其他相关问题(这里、这里和那里以及其他网站,例如这个和那个),但找不到令人满意的(或有效的!)解决方案。
我有一组插件:P1、P2 和 P3。P1 导出一些由 P2 使用的类。P2 还导出了 P3 使用的其他类和接口。特别是,P2 定义并导出了接口 MyInterface,其实现类 MyInterfaceImpl 实现了 MyInterface。P3 是一个应用程序,因此包含一个类 Launcher 实现 IApplication并定义公共对象 start(IApplicationContext)方法。一切都编译得很好。当我从 Eclipse 将 Launcher 作为 Eclipse 应用程序运行时,它运行良好。启动器使用MyInterface和MyInterfaceImpl很好。
现在,根据各种帖子,我使用以下(简单)代码以编程方式运行我的应用程序,这似乎是运行 Equinox/Eclipse 应用程序的一种“好的”方式:
void callApplication() {
final String[] args =
new String[] {
"-application",
"Launcher",
... };
EclipseStarter.run(args, null);
}
同样,这段代码运行良好,我可以“看到”我的应用程序运行并产生预期的结果。
现在,我的问题来了:我想获得一个MyInterfaceImpl的实例,该实例由我的应用程序构建,在 Equinox 中运行,回到“外部”Java 代码中。我天真的解决方案是在public Object start(IApplicationContext)方法中返回这个对象并修改我的调用代码如下:
MyInterface callApplication() {
final String[] args =
new String[] {
"-application",
"Launcher",
... };
return (MyInterface) EclipseStarter.run(args, null);
}
但这种幼稚的解决方案行不通。我收到java.lang.ClassCastException: MyInterfaceImpl cannot be cast to MyInterface。想一想,这是有道理的,因为在callApplication()结束时,我有两个“版本”对 { MyInterface,MyInterfaceImpl }:一个来自“外部”Java 代码,由 JVM 类加载器加载,另一个另一个来自 Equinox,由 Equinox 类加载器加载。我修改了代码以打印返回对象和MyInterface的类加载器:
final Object o = EclipseStarter.run(args, null);
System.out.println(o.getClass().getClassLoader());
System.out.println(MyInterface.class.getClassLoader());
事实上,我得到了:
org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@7e66458c[P2:1.5.0(id=413)]
sun.misc.Launcher$AppClassLoader@1efc3d2
请注意,返回对象的类加载器据说来自 P2,正如预期的那样,因为 P2 是定义和导出MyInterface和MyInterfaceImpl的插件。
我尝试了不同的方法来获得“兼容”的 { MyInterface , MyInterfaceImpl } 对,但到目前为止没有运气(我总是得到相同的java.lang.ClassCastException: MyInterfaceImpl cannot be cast to MyInterface):
我尝试设置属性-Dorg.osgi.framework.bootdelegation=* -Dorg.osgi.framework.system.packages.extra=MyInterface,MyInterfaceImpl。
我还尝试在start()方法中拦截DefaultClassLoader 。
所以,我的问题是:有没有办法让Java程序使用项目中定义的一些类,它也是一个插件并导出这些类,与以编程方式启动的Eclipse实例交换这些类的实例? 谢谢!