How to dynamically load Java classes in Runtime in OSGI?

We perform POC in our project, where we send a request based on SOAP and accordingly receive a SOAP response from the web service. We strive to use the webservices template (client API) provided by the spring framework in our application. In accordance with our architecture, we create an OSGI-compatible package (for our code that uses the web service template API to interact with the web service), which is then deployed to the Apache Felix container. We also installed all OSGI-compatible dependent packages in the Felix container to resolve all dependencies.

According to the webservices pattern, the default web service message sender is HttpUrlConnectionMessageSender, which is dynamically loaded at run time by the class loader. In my understanding, we get the following exception, because the Felix container cannot load the class from the OSGI dependent package (the web service package contains HttpUrlConnectionMessageSender). Please refer to the exception logs below.

* org.springframework.beans.factory.BeanInitializationException: Could not find default strategy class for interface [org.springframework.ws.transport.WebServiceMessageSender]; nested exception is java.lang.ClassNotFoundException:org.springframework.ws.transport.http.HttpUrlConnectionMessageSender at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:126) at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:90) at org.springframework.ws.client.core.WebServiceTemplate.initMessageSenders(WebServiceTemplate.java:320) at org.springframework.ws.client.core.WebServiceTemplate.initDefaultStrategies(WebServiceTemplate.java:306) at org.springframework.ws.client.core.WebServiceTemplate.<init>(WebServiceTemplate.java:143) at test.soapservice.service.SOAPServiceImpl.<init>(SOAPServiceImpl.java:40) at test.soapservice.service.SOAPServiceActivator.start(SOAPServiceActivator.java:17) at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:641) at org.apache.felix.framework.Felix.activateBundle(Felix.java:1977) at org.apache.felix.framework.Felix.startBundle(Felix.java:1895) at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:944) at org.apache.felix.gogo.command.Basic.start(Basic.java:729) 

Called: java.lang.ClassNotFoundException: org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

  at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at org.springframework.util.ClassUtils.forName(ClassUtils.java:211) at org.springframework.util.ClassUtils.forName(ClassUtils.java:164) at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:114) 

According to my understanding, a Felix container cannot dynamically load a class using ClassUtils.forName (), which exists in another bundle. I see this as a collaboration issue when the current package has a different classloader, rather than a dependent classloader.

Has anyone in this community encountered the same exception? If so, what steps have you taken to resolve the runtime class dependencies? Please share your thoughts / pointers to solve the above problem. A quick response will be highly appreciated and can help us make our POC a success.

Thanks in advance, Mridul Chopra

+4
source share
1 answer

Loading classes in the form of Class.forName() not a problem in any OSGi container. The problem is that the MANIFEST.MF file does not contain the correct import declarations. One package should export the org.springframework.ws.transport package, while your package should import the same package.

If you use Maven to create your package, you can use the Felix Bundle Plugin to create the correct manifest information.

 <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> <instructions> <Private-Package>my.private.package.*</Private-Package> </instructions> </configuration> </plugin> </plugins> 

This should check your code and add an import for something that is not in the scope of your "private" package. Another thing you have to do to make this work is to set the packaging type to bundle .

 <packaging>bundle</packaging> 

But the examples above are when you use Maven as a build tool. If you are using Gradle, you can use the Gradle OSGi plugin to create a manifest. Or, if you use Ant, you can use the SpringSource Bundlor project (by the way, it also has a Maven plugin).

0
source

Source: https://habr.com/ru/post/1401532/


All Articles