0

我面临的问题是“普通”Java、Equinox 以及两者之间的通信的组合。我已经阅读了其他相关问题(这里这里那里以及其他网站,例如这个那个),但找不到令人满意的(或有效的!)解决方案。

我有一组插件:P1、P2 和 P3。P1 导出一些由 P2 使用的类。P2 还导出了 P3 使用的其他类和接口。特别是,P2 定义并导出了接口 MyInterface,其实现类 MyInterfaceImpl 实现了 MyInterface。P3 是一个应用程序,因此包含一个类 Launcher 实现 IApplication并定义公共对象 start(IApplicationContext)方法。一切都编译得很好。当我从 Eclipse 将 Launcher 作为 Eclipse 应用程序运行时,它运行良好。启动器使用MyInterfaceMyInterfaceImpl很好。

现在,根据各种帖子,我使用以下(简单)代码以编程方式运行我的应用程序,这似乎是运行 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()结束时,我有两个“版本”对 { MyInterfaceMyInterfaceImpl }:一个来自“外部”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 是定义和导出MyInterfaceMyInterfaceImpl的插件。

我尝试了不同的方法来获得“兼容”的 { 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实例交换这些类的实例? 谢谢!

4

1 回答 1

1

啊,这个很棘手。我建议重新构建您的应用程序并为所有内容使用插件,但这并不能回答您的问题。

现在,您要做的是首先删除接口定义表单 P2 并将其添加到您的原始(非 OSGi)JAR 中,最好单独放在一个包中,比如说com.example.api. 然后,添加-Dorg.osgi.framework.system.packages.extra=com.example.api;还为该包在 P2 和 P3 中添加导入。

希望这可以帮助。

于 2013-08-06T18:14:47.827 回答