我刚刚开始在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。
答案 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 workspaces或standalone 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,但仅供参考:
转到插件清单编辑器的“自动管理依赖关系”部分。
确保编译依赖项列在插件开发类路径列表中。
确保选择Import-Package
单选按钮。 Require-Bundle
促进紧密耦合和高扇出,应该避免。
每次更改代码时,都需要单击添加依赖项超链接。这将重新计算您的包导入。
对于将来,您可能希望考虑使用Eclipse的Bndtools plugin来开发OSGi包而不是Eclipse PDE。 Bndtools通常为PDG提供比PDE更复杂(和更新)的支持,因为它建立在bnd之上,而bnd是OSGi规范的几个部分的参考实现。