java8_OSGI:NoClassDefFoundError:javafx / collections / MapChangeListener

时间:2018-04-10 08:12:33

标签: java-8 eclipse-plugin osgi osgi-bundle

我刚刚开始在OSKI上开发Eclipse Kura项目,我试图实现一个hashmap监听器:

// Use Java Collections to create the List.
Map<String,String> map = new HashMap<String,String>();

// Now add observability by wrapping it with ObservableList.
ObservableMap<String,String> observableMap = FXCollections.observableMap(map);
observableMap.addListener(new MapChangeListener() {
    @Override
    public void onChanged(MapChangeListener.Change change) {
        System.out.println("Detected a change! ");
        logerKuraPI("Detected a change! ");
    }
});

// Changes to the observableMap WILL be reported.
observableMap.put("key 1","value 1");
System.out.println("Size: "+observableMap.size());
logerKuraPI("Size: "+observableMap.size());

// Changes to the underlying map will NOT be reported.
map.put("key 2","value 2");
System.out.println("Size: "+observableMap.size());
logerKuraPI("Size: "+observableMap.size());

当我在Intellij IDEA中以简单的main运行此代码时,它工作正常,但是当我在eclipse,OSGI项目(Eclipse Kura)中实现时,我收到此错误:

java.lang.NoClassDefFoundError: javafx/collections/MapChangeListener
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at org.eclipse.equinox.internal.ds.model.ServiceComponent.createInstance(ServiceComponent.java:493)
    at org.eclipse.equinox.internal.ds.model.ServiceComponentProp.createInstance(ServiceComponentProp.java:270)
    at org.eclipse.equinox.internal.ds.model.ServiceComponentProp.build(ServiceComponentProp.java:331)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponent(InstanceProcess.java:620)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponents(InstanceProcess.java:197)
    at org.eclipse.equinox.internal.ds.Resolver.getEligible(Resolver.java:343)
    at org.eclipse.equinox.internal.ds.SCRManager.serviceChanged(SCRManager.java:222)
    at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:109)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:915)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:862)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:127)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:225)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:464)
    at org.eclipse.equinox.internal.ds.InstanceProcess.registerService(InstanceProcess.java:536)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponents(InstanceProcess.java:213)
    at org.eclipse.equinox.internal.ds.Resolver.buildNewlySatisfied(Resolver.java:473)
    at org.eclipse.equinox.internal.ds.Resolver.enableComponents(Resolver.java:217)
    at org.eclipse.equinox.internal.ds.SCRManager.performWork(SCRManager.java:816)
    at org.eclipse.equinox.internal.ds.SCRManager$QueuedJob.dispatch(SCRManager.java:783)
    at org.eclipse.equinox.internal.ds.WorkThread.run(WorkThread.java:89)
    at org.eclipse.equinox.internal.util.impl.tpt.threadpool.Executor.run(Executor.java:70)
Caused by: java.lang.ClassNotFoundException: javafx.collections.MapChangeListener cannot be found by fileloger_1.0.0.qualifier
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:461)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

不要忘记,当我编译时,我在eclipse中没有得到任何错误并且它识别包,但是当我运行时我得到了那些错误。 我正在使用Java8。

1 个答案:

答案 0 :(得分:2)

这部分堆栈跟踪:

Caused by: java.lang.ClassNotFoundException: javafx.collections.MapChangeListener cannot be found by fileloger_1.0.0.qualifier
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:461)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

似乎表明Equinox正在尝试在您的包中找到该类,而不是通过委托。这意味着您的“包”可能缺少一些依赖关系元数据,特别是包导入。

OSGi捆绑包通过导出和导入的包系统共享API包。作为解决过程的一部分,OSGi框架将导入连接导出到导出。这就是您的OSGi包处于 RESOLVED 状态而不是 INSTALLED 状态的含义。

您在捆绑包中使用的所有程序包(以java.*开头的所有程序包必须由该捆绑包导入。在这种情况下,您需要的导入是javafx.collections。您将找到向您展示如何编写import语句的示例,但您绝对应该手动执行此操作。有许多工具可以自动生成OSGi包的包清单,包括正确的包导入语句。

如果您使用的是Maven,我会推荐bnd-maven-plugin,或者如果您使用的是Gradle,那么您可以使用相关的bnd插件bnd workspacesstandalone projects

生成的清单最终应该输入如下条目:

Import-Package: javafx.collections

除此之外,您还需要确保框架中的某些内容导致javafx.collections导出。通常这会涉及添加提供相关API包的包,但我怀疑(我不是JavaFX用户)必须在OSGi框架之外安装JavaFX。如果是这种情况,那么您需要将javafx.* API包添加为系统包中的导出(OSGi运行时中代表OSGi框架的包)。这可以使用org.osgi.framework.system.packages.extra启动属性来列出包(由,个字符分隔的包名列表)。

更新

您对此帖的回复表明您正在使用Eclipse PDE。 PDE不如bnd灵活,并且不会在构建中自动为您进行此分析。因此,如果您忘记执行这些步骤,最终可能会出现错误的元数据,但它仍然能够在IDE中自动确定捆绑包的依赖关系。相关文档为available from eclipse,但仅供参考:

  1. 转到插件清单编辑器的“自动管理依赖关系”部分。

  2. 确保编译依赖项列在插件开发类路径列表中。

  3. 确保选择Import-Package单选按钮。 Require-Bundle促进紧密耦合和高扇出,应该避免。

  4. 每次更改代码时,都需要单击添加依赖项超链接。这将重新计算您的包导入。

  5. 对于将来,您可能希望考虑使用Eclipse的Bndtools plugin来开发OSGi包而不是Eclipse PDE。 Bndtools通常为PDG提供比PDE更复杂(和更新)的支持,因为它建立在bnd之上,而bnd是OSGi规范的几个部分的参考实现。