问题
I have a class which runs an Equinox framework. Now I would like to get an Object (defined in one of the bundles) that is returned by a service out of the framework.
Unfortunately, I get a LinkageError and have no idea how to get rid of it. Is it even possible to let a service return a proper object to non-bundle code?
Here is the full story:
ParserDTOBundle is a bundle that defines the class ParserDTO and exports the corresponding package.
In another bundle, ParserServiceBundle, I define a service called ParserService. This bundle imports the package of the ParserDTO. The function getDTO() of ParserService creates a new ParserDTO object and returns it.
Now I created another class which starts an Equinox framework and loads both bundles from a directory:
...
EclipseStarter.setInitialProperties(frameworkPropertiesMap);
bundleContext = EclipseStarter.startup(new String[] { "-console", "-dev", "bin" }, null);
bundleContext.installBundle("file:/" + dir + "ParserDTOBundle-0.0.1-SNAPSHOT.jar");
Bundle service = bundleContext.installBundle("file:/" + dir + "ParserServiceBundle-0.0.1-SNAPSHOT.jar");
service.start();
ServiceReference serviceReference = bundleContext.getServiceReference(ParserService.class.getName());
if (serviceReference != null) {
ParserService ps = (ParserService) bundleContext.getService(serviceReference);
if (ps != null) {
ParserDTO dto = ps.getDTO();
System.out.println(dto.getValue());
}
}
The above described class is part of a non-bundle Maven project. The run of the above class fails with:
Exception in thread "main" java.lang.LinkageError: loader constraint violation: loader (instance of sun/misc/Launcher$AppClassLoader) previously initiated loading for a different type with name "de/ParserDTO"
Interestingly, I get this error at the System.out.println and not the line before. The class loader of the ParserDTO class in my main class is obviously different from the class loader of the object dto.
How can I get the information stored in dto?? Is that even possible?? Do I have to 1.) hand my normal class loader to the bundle or 2.) use basic datatypes instead or 3.) some completly other way??
Thank you all in advance! Sebastian
回答1:
So the class ParserDTO
has been independently loaded by two different class loaders: the one inside your bundle, and the application classloader from your "outer" application. You need to make sure it is loaded only by one classloader.
When this problem occurs with two ordinary bundles, the key is to make sure that one bundle exports the package and the other imports it (OR they both import it from a third bundle).
However in this case you are interacting between the outer application and bundles inside OSGi. There is a hard rule: the OSGi framework cannot import packages from bundles inside OSGi. So the package has to be present in the outer application and exported from the system bundle by adding it to FRAMEWORK_SYSTEMPACKAGES_EXTRA
. Also make sure that the bundle imports that package rather than having its own copy.
BTW... you might want to choose a better name for the package than just de
! I don't think that you are the only Java developer in Germany, so you don't own that namespace ;-)
来源:https://stackoverflow.com/questions/11413235/how-to-get-a-bundle-object-returned-by-a-service-out-of-the-equinox-framework