felix 上的 OSGI 类转换异常
我对 osgi 相当陌生,正在尝试一起获得功能性的概念证明。
设置是,我的通用 api 是在一个创造性地命名为 common-api.jar 的包中创建的,没有包激活器,但它导出了所有接口。在这种情况下,我们感兴趣的是 DatabaseService.java。
然后我有第二个捆绑包,名为 systemx-database-service。它实现了数据库服务接口。这工作得很好,因为在实现包的激活器中我测试了与数据库的连接并选择了一些任意值。我还注册了我希望可供其他捆绑包使用的服务,如下所示:
context.registerService(DatabaseService.class.getName(), new SystemDatabaseServiceImpl(context), new Properties());
基本思想是,当您查找数据库服务的服务引用时,您将得到 SystemDatabaseService 实现。
当我执行检查服务时,输出如下:
-> inspect s c 69
System Database Service (69) provides services:
----------------------------------------------
objectClass = za.co.xxx.xxx.common.api.DatabaseService
service.id = 39
这会让我相信,如果我在测试包中执行此操作:
context.getService(context.getServiceReference(DatabaseService.class));
我应该返回 DatabaseService.class 的实例,但可惜没有这样的运气。它似乎只是找不到该服务。跟着我,我的故事变得更奇怪了。
想到除了向上我没有其他地方可以去,我写了这个怪物:
for (Bundle bundle : bundles) {
if (bundle.getSymbolicName().equals("za.co.xxx.xxx.database-service")) {
ServiceReference[] registeredServices = bundle.getRegisteredServices();
for (ServiceReference ref : registeredServices) {
DatabaseService service = (DatabaseService) context.getService(ref);
// use service here.
}
}
}
}
现在我实际上可以看到服务引用,但我得到这个错误,
java.lang.ClassCastException: za.co.xxx.xxx.database.service.impl.SystemDatabaseServiceImpl cannot be cast to za.co.xxx.xx.common.api.DatabaseService
这是疯狂的,因为实现明确地实现了接口!
任何帮助将不胜感激。请记住,我对 osgi 的思维方式非常陌生,所以我在这里的整个方法可能有缺陷。
哦。如果有人想要清单,我可以发布它们。我正在使用 maven-bnd-plugin 在 felix 上构建和执行。
谢谢尼科
i'm fairly new to osgi and am trying to get a functional proof of concept together.
The setup is that my common api is created in a bundle creatively named common-api.jar with no bundle activator, but it exports all it's interfaces. the one of interest in this situation is DatabaseService.java.
I then have a Second bundle called systemx-database-service. That implements the database service interface. this works fine as in the activator of the implementation bundle i test the connection to the database and select some arbitraty values. I also register the service i want to be available to the other bundle's like so:
context.registerService(DatabaseService.class.getName(), new SystemDatabaseServiceImpl(context), new Properties());
The basic idea being when you look for a service reference for a Database service you'll get back the SystemDatabaseService implementation.
When i do a inspect service the output it this:
-> inspect s c 69
System Database Service (69) provides services:
----------------------------------------------
objectClass = za.co.xxx.xxx.common.api.DatabaseService
service.id = 39
which would lead me to believe that if i do this in a test bundle:
context.getService(context.getServiceReference(DatabaseService.class));
i should get back an instance of DatabaseService.class, but alas no such luck. it simply seems like it cannot find the service. stick with me here my story gets stranger.
figuring there is no where to go but up i wrote this monstrosity:
for (Bundle bundle : bundles) {
if (bundle.getSymbolicName().equals("za.co.xxx.xxx.database-service")) {
ServiceReference[] registeredServices = bundle.getRegisteredServices();
for (ServiceReference ref : registeredServices) {
DatabaseService service = (DatabaseService) context.getService(ref);
// use service here.
}
}
}
}
now i can actually see the service reference, but i get this error
java.lang.ClassCastException: za.co.xxx.xxx.database.service.impl.SystemDatabaseServiceImpl cannot be cast to za.co.xxx.xx.common.api.DatabaseService
which is crazy since the implementation clearly implements the interface!
Any help would be appreciated. Please keep in mind i'm very new at the osgi way of thinking so my whole approach here might be flawed.
oh. if anyone wants the manifests i can post them. and i'm using the maven-bnd-plugin to build and executing on felix.
thanks
Nico
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
测试包必须解析为与 SystemDatabaseServiceImpl 相同的 DatabaseService 接口导入。如果没有发生这种情况,则 getServiceReference 会记录即使找到服务也会返回 null。通过手动定位包并尝试定位服务和转换,您将展示为什么 getServiceReference 会以这种方式运行:如果它返回任意服务,Java 转换就会失败。
我建议在 impl 包和测试包中打印 DatabaseService.class.getClassLoader() 以证明它们是否是同一个包。如果不是,那么您需要调整 OSGi MANIFEST.MF 元数据以确保它们具有一致的接口类视图。
例如,DatabaseService 接口是否包含在测试包和 impl 包中?如果是,您需要将该接口移至 impl 捆绑包(和 Export-Package)或第三个接口捆绑包和 Export-Package。然后,将其他捆绑包调整为 Import-Package。
The test bundle must resolve to the same import of the DatabaseService interface as the SystemDatabaseServiceImpl. If this does not occur, then getServiceReference documents that it will return null even if a service is found. By locating the bundle manually and attempting to locate the service and cast, you're showing why getServiceReference behaves in this way: if it returned arbitrary services, Java casts would fail.
I would recommend printing DatabaseService.class.getClassLoader() in both the impl bundle and test bundle to prove if they're the same bundle. If they're not, then you need to adjust your OSGi MANIFEST.MF metadata to ensure that they have a consistent view of the interface class.
For example, is the DatabaseService interface included in both the test and impl bundles? If yes, you need to move that interface to either the impl bundle (and Export-Package) or to a third interface bundle and Export-Package. Then, adjust the other bundles to Import-Package.