要点: 我在OSGi包中看到OSGi环境中运行时可用的类。
上下文
我的RCP应用程序将对象存储到磁盘,其中涉及存储每个对象的类名。想法是在加载时,将使用写入磁盘的类名重新实例化对象。主AppBundle
执行存储操作。存储的对象中包括由其他包提供的类型的对象,例如Bundle1
和Bundle2
。
问题:
当我尝试基于存储的名称读取类信息时,尽管OSGi运行时中包含相同的bundle及其提供的类,但是我的AppBundle
中看不到类信息。我已经包含了处理存储和读取的代码示意图。
public class Storage{
transient Object[] objs = new Object[3];
{
// Something link the following happens dynamically during the application
objs[0] = new AppBundleClass();
objs[1] = new Bundle1Class();
objs[2] = new Bundle2Class();
}
// Persisted to disk
private String[] objTypes;
public void saveToDisk(){
objTypes = new String[objs.length];
for (int i = 0; i < objTypes.length; i++)
objTypes[i] = objs[i].getClass().getCanonicalName();
}
public void afterLoadingFromDisk(){
objs = new Object[objTypes.length];
for (int i = 0; i < objs.length; i++){
Class<?> klass = Class.forName(objTypes[i]);
// **** Throws error above ****
objs = loadByClass(klass);
// Custom method that works for classes withing the app.
}
}
}
AppBundle
对Bundle1
或Bundle2
没有构建依赖关系。这个想法是应用程序的用户可以在运行时根据需要激活不同的包。
尝试解决方案:
我怀疑问题与OSGi为每个包使用不同的类加载器以及AppBundle
的类加载器无法解析Bundle1Class
有关,因为它不是通过指定的编译时依赖性bundle-dependencies或包导入。所以,我尝试了以下内容。
Bundle1/MANIFEST.MF
DynamicImport-Package: *
(to allow packages from this bundle to be dynamically visible)
AppBundle/MANIFEST.MF
Eclipse-BuddyPolicy: global
(to allow this bundle to be able to resolve any class available in the OSGi runtime)
预期行为
Bundle1
和Bundle2
中的类现在应该对AppBundle
可见。
实际行为 奇怪的是,时不时(相当随机),这是有效的。但是,大多数时候,我遇到了关于没有找到的课程的错误。
答案 0 :(得分:2)
您不需要BuddyPolicy。只需确保Bundle1和Bundle2导出包,AppBundle具有DynamicImport-Package: *
。
请记住,这种方法只有在每个此类软件包仅由一个软件包导出时才有效。一般来说,通过类名识别一个类是OSGi中一个有缺陷的方法。
更好的方法是让每个bundle处理它知道的类并自己进行序列化。这也可以更好地匹配模块边界。
答案 1 :(得分:1)
我同意基督徒的观点,认为纯粹通过名字来确定一个课程是问题的根源,但会提供不同的解决方案。
在任何模块化环境中,类名称不足以标识类,因为多个包可以知道相同的名称。您的应用程序当前正在保存仅附加了类名的数据,因此只需更改此选项即可保存包标识由Bundle-SymbolicName
和Bundle-Version
组成的类名和包ID。
加载时,使用Bundle-SymbolicName
和Bundle-Version
查找匹配的Bundle
对象,然后调用Bundle.loadClass(..)
按名称加载类。
您不需要导出包含持久化类的包,也不需要将此包导入持久性框架包。