JAXB + OSGi with Java 11 - java

I'm trying to load the JAXB modules as OSGi bundles with Java 11 and Apache Felix using a POM-first approach (the OSGi meta data gets generated).
First I tried with:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-osgi</artifactId>
<version>2.3.3</version>
</dependency>
but this gives me the following runtime exception:
SCHWERWIEGEND: Implementation of JAXB-API has not been found on module path or classpath.
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]
It might be related to the following issue, but I'm not sure: https://github.com/eclipse-ee4j/jaxb-api/issues/78
So I tried with v3.0.0 but now one of my annotation processory which generate an XML document using JAXB, fails:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project my-module: Compilation failure
Implementation of JAXB-API has not been found on module path or classpath.
I noticed that jaxb-osgi-3.0.0.jar does not provide the com.sun.xml.bind package anymore
I also tried to migrate from javax.xml.bind to jakarta.xml.bind, but the Maven Plugins, which generate POJO classes from XSDs, don't seem to be ready yet at the time of writing (neither org.jvnet.jaxb2.maven2:maven-jaxb2-plugin nor org.codehaus.mojo:jaxb2-maven-plugin).
My questions:
Where can I get the com.sun.xml.bind from?
How do the jaxb-osgi and jaxb-impl modules relate?
How is this all supposed to work?
How can I proceed?
Update - background information
I have the following setup based on the Extender Pattern:
core extender module M:
provides some JAXB classes
a BundleTracker to unmarshal XML documents from a META-INF sub-directory of some bundles X, Y, Z
an abstract custom annotation processor to marshal the XML documents
extension modules A, B, C:
provide additional JAXB classes (generated from XSDs)
extensions are registered using Declarative Services
custom annotations
annotation processors to convert the annotation attributes to JAXB based models and generate the XML-document at the expected place
extendee modules X, Y, Z
using the annotation of modules A, B, C
using the annotation processors of A, B, C to generate the XML-documents
Goal: it should be easy to create extendee modules such as X, Y, Z
Everything works fine with Java SE 8 where JAXB is still bundled with the JRE.
Update 1
Because the Maven plugins are not ready I'm stuck with v2.3.3 for now.
I changed the following:
I'm providing a classloader when calling JAXBContext.newInstance
I added the following configuration to the maven-bundle-plugin in several modules:
com.sun.xml.bind.v2, *
This solved the java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory issues (it doesn't seem to be the correct solution for this, though), but now the ObjectFactory cannot be located though they were generated.
Update 2
I'm using now a modified jaxb-osgi bundle (see issue) and Apache Aries SPI Fly Dynamic Weaving Bundle (1.3.2) (the reference implementation of the OSGi ServiceLoader Mediator specification) and I added the following requirements to the core module M:
Require-Capability: [...],osgi.extender;filter:="(o
sgi.extender=osgi.serviceloader.processor)",osgi.serviceloader;filter:=
"(osgi.serviceloader=javax.xml.bind.JAXBContextFactory)";cardinality:=m
ultiple,[...]"
The services seem to get detected:
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.xml.bind.v2.JAXBContextFactory of service javax.xml.bind.JAXBContextFactory in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.code_injector.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.locator.SourceLocationAddOn of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.sync.SynchronizedMethodAddOn of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.at_generated.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.episode.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.accessors.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
But I still get:
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory not found by
Why does it try to load the hard-coded default com.sun.xml.bind.v2.ContextFactory instead of com.sun.xml.bind.v2.JAXBContextFactory via ServiceLoader?

Since each OSGI bundle uses its own classloader the JAXB API is not able to use the standard ServiceLoader to locate the JAXB implementation. However since version 2.2.2 the JAXB API can use osgi-resource-locator as a fallback.
Therefore, in order to use JAXB on Java 11, you just need to:
Add a dependency on the javax.xml.bind and org.glassfish.hk2.osgiresourcelocator packages,
Deploy the osgi-resource-locator and jaxb-osgi bundles together with your bundle.
Remark: if you want to use MOXy, you need additional steps, since MOXy does not ship with a META-INF/services/javax.xml.bind.JAXBContext file (cf. this answer).

Related

Servicemix Spring 4 wiring issue

Edit:
To better/shorter folmulate my main question;
Is it possible to get an OSGI application running using spring-osgi (1.2.1) and Spring 4 at the same time? And if so, how?
Original:
I am trying to make servicemix 6.1.3 work with Spring 4.
I know support has been officially dropped as of Spring version 3 but I need spring 4 for security reasons and frankly keeping our application up to date with newer functionality.
So I imported the required servicemix spring V4 bundles.
The issue here is that our application also uses the spring-osgi functionality (so not the abovementioned osgi-ified bundles by servicemix but the actual spring-osgi bundles which have V 1.2.1 as seen below)
The error:
Error executing command: Error executing command on bundles:
Unable to execute command on bundle 352: Uses constraint violation. Unable to resolve bundle revision my.app.service [352.7] because it is exposed to package 'org.springframework.context.support' from bundle revisions org.apache.servicemix.bundles.spring-
context [240.0] and org.apache.servicemix.bundles.spring-context [105.0] via two dependency chains.
Chain 1:
my.app.service [352.7]
import: (&(osgi.wiring.package=org.springframework.context.support)(version>=4.2.0)(version<=4.4.0))
|
export: osgi.wiring.package=org.springframework.context.support
org.apache.servicemix.bundles.spring-context [240.0]
Chain 2:
my.app.service [352.7]
import: (&(osgi.wiring.package=org.springframework.osgi.web.context.support)(version>=1.2.1))
|
export: osgi.wiring.package=org.springframework.osgi.web.context.support; uses:=org.springframework.osgi.context.support
org.springframework.osgi.web [252.0]
import: (&(osgi.wiring.package=org.springframework.osgi.context.support)(version>=1.2.1)(version<=1.2.1))
|
export: osgi.wiring.package=org.springframework.osgi.context.support; uses:=org.springframework.context.support
org.springframework.osgi.core [109.0]
import: (&(osgi.wiring.package=org.springframework.context.support)(version>=2.5.6)(!(version>=4.0.0)))
|
export: osgi.wiring.package=org.springframework.context.support
org.apache.servicemix.bundles.spring-context [105.0]
Now as you can see the issue is that I have spring-context twice running in servicemix. Once from the default installation [105] (I expect on the background a lot of servicemix's bundles (camel, activeMQ, etc) are using Spring 3, hence I dont want to remove them in fear of other issues; but if you know better, please enlighten me) and a Spring V4 bundle [240].
Our usage of spring-osgi requires us to use its bundles which are hardcoded to use "org.springframework.context.support version>=2.5.6 !version>=4.0.0".
Now my question;
- Is there a way around this? To force org.springframework.osgi.core to use the spring-context V4 bundle? Or is it just impossible to use Spring 4 at the same time as Spring 3's OSGI bundles?
Additional info:
I used the following in my pom's maven-bundle-plugin import-Package tag to enforce usage of Spring 4: (spring.version=[4.2,4.4])
org.springframework.context.support;version="${spring.version}",
And in the parent pom has the following in the dependency-management section.
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.spring-context</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
Edit 2:
Maybe I can manually bypass the org.springframework.context.support (version>=2.5.6)(!(version>=4.0.0)) requirement by downloading the spring osgi 1.2.x branch from github, change the in the pom and recompile.
Still obviously this isnt a good solution at all sice im hacking myself through to unsupported versions, so please advise.

starting slf4j bundle doesn't start on felix

I have felix-framework-5.0.1 and I'm trying to start slf4j-api-1.6.0.jar bundle into felix isgi container.
in felix console I'm typing install file:bundle/slf4j-api-1.6.0.jar
I'm getting a message Bundle ID: 42
then I'm trying to start the bundle start 42
I'm getting the message
org.osgi.framework.BundleException: Unable to resolve slf4j.api [42](R 42.0): missing requirement [slf4j.api [42](R 42.0)] osgi.wiring.package; (&(osgi.wiring.p
ackage=org.slf4j.impl)(version>=1.5.5)) Unresolved requirements: [[slf4j.api [42](R 42.0)] osgi.wiring.package; (&(osgi.wiring.package=org.slf4j.impl)(version>=
1.5.5))]
g!
Can any body help me? how can I start slf4j bundle into felix?
slf4j-api needs org.slf4j.impl package. This package is included into every slf4j implementations like slf4j-simple, slf4j-logback, etc.
The implementation bundles need org.slf4j package that comes from the API artifact. There is a cross-reference. This can work only due to the reason that implementations are fragment bundles of the API. When the implementation is installed together with the API, they will have a common classloader and they will be resolved together. Both of their requirements will be satisfied.
In short: You must choose one of the implementations and install that as well. E.g.: slf4j-simple.
You should use the same version of API and implementation to satisfy their "cross requirement".
Your library contains the following 3 packages (link):
org.slf4j
org.slf4j.helpers
org.slf4j.spi
but you have to have an additional library that will contain org.slf4j.impl package.
Also, from manifest file you can see what packages are exported (Export-Package) (they are visible by other bundles) and what packages are imported (Import-Package) (they have to be accessible for the given bundle). Sometimes the given package have to be from bundle with the correct version.
If you cannot find correct bundle maybe this page will help you.

Compatiblity Issue of asm 3.1 and org.eclipse.persistence.asm-2.3.2.jar (jersey-moxy 1.15)

A similar problem as in Compatibility Issue of ASM 3.1 and HIbernate and JAX-RS
seems to have hit me:
my Jersey / JPA based rest application which also uses jersey-moxy (version 1.15 of jersey) throws an error:
Caused by: java.lang.NoSuchMethodError: org.eclipse.persistence.internal.libraries.asm.ClassReader.accept(Lorg/eclipse/persistence/internal/libraries/asm/ClassVisitor;[Lorg/eclipse/persistence/internal/libraries/asm/Attribute;Z)V
My maven dependency list shows:
asm-3.1.jar
jersey-moxy-1.15.jar
org.eclipse.persistence.asm-2.3.2.jar
if i remove jersey-moxy 1.15 from the dependency the problem goes away but then I can't use the extra MOXy features.
If exclude the org.eclipse.persistence.asm dependency i get:
Internal Exception: java.lang.SecurityException: class "org.eclipse.persistence.sessions.factories.SessionManager"'s signer information does not match signer information of other classes in the same package
What would be a solution to this situation?
This issue isn't the same as Compatibility Issue of ASM 3.1 and HIbernate and JAX-RS. EclipseLink specifically ships a repackaged version of ASM to specifically avoid this issue.
I'm not familiar with the jersey-moxy-1.15.jar (could you provide additional info on this one?). MOXy requires the following bundles:
org.eclipse.persistence.moxy_2.4.1.v20121003-ad44345.jar
org.eclipse.persistence.core_2.4.1.v20121003-ad44345.jar
org.eclipse.persistence.asm_3.3.1.v201206041142.jar
If you are using MOXy for JSON binding (see http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html), then you also require the following bundle:
org.eclipse.persistence.antlr_3.2.0.v201206041011.jar

Camel - unmarshal().serialization() - ClassNotFoundException

I'm trying to unmarshal with serialization method a bean that is not the current bundle but in a commons components bundle.
I get the following error when camel tries to unmarshal my bean :
22:43:11,865 | ERROR | nModule-thread-1 | DefaultErrorHandler | 89 - org.apache.camel.camel-core - 2.8.0.fuse-06-11 | Failed
delivery for exchangeId: ID-ITEM-64684-49962-1354223882336-2-1.
Exhausted after delivery attempt: 1 caught:
java.lang.ClassNotFoundException: commons.InformationInput
java.lang.ClassNotFoundException: commons.InformationInput at
java.net.URLClassLoader$1.run(URLClassLoader.java:202)[:1.6.0_33] at
java.security.AccessController.doPrivileged(Native Method)[:1.6.0_33]
at
java.net.URLClassLoader.findClass(URLClassLoader.java:190)[:1.6.0_33]
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)[:1.6.0_33]http://stackoverflow.com/questions/6749334/osgi-bundle-access-spring-context-file-from-another-bundle
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)[:1.6.0_33]
at
org.apache.felix.framework.ModuleImpl.doImplicitBootDelegation(ModuleImpl.java:1610)
at
org.apache.felix.framework.ModuleImpl.searchDynamicImports(ModuleImpl.java:1547)
My bundle containing the bean is correctly started and i've defined the commons package in the Export-Package of the bundle definition
Does anyone managed to such thing ?
This sometimes occurs when the bundle that is serializing/deserializing classes does not know in advance what packages must be imported.
One workaround is to use DynamicImport-Package. For example:
DynamicImport-Package: *
This then means the bundle can import classes in any package, but beware of the costs (see the linked article).
This sounds similar to Hibernate issues an OSGi environment where it fails because of class loading issues. I would recommend something classed class buddy loading. in the Manifest of your commons bundle that contains the class add this
Eclipse-BuddyPolicy:registered
Then in your dependent buddy make sure you have it added as a dependent bundle and this to its manifest.
Eclipse-RegisterBuddy:com.nameofmycommonbundle
This should solve your problem.
Here is a reference to hibernate reference
I find a workaroud by enabling dynamicimport on camel-core bundle.
This can be done on karaf console : dev:dynamicimport <camel-core-bundle-id>

Getting started with bundle DI in an OSGi environment

I have been developing an application with Apache Felix as my OSGi runtime for a while and up until now progress has been great. However, I want to now adopt dependancy injection and the "default" mechanism with Apache Felix seems to be iPOJOs.
However, I've found that the documentation and tutorials around about Apache felix are too weak and I've not managed to get anywhere. So I am prepared to change, but first of all I'd better explain the (very simple) think I'm trying to do.
Given two bundles;
Consumer bundle
package bundles.consumer;
class Consumer implements BundleActivator{
#Inject
private Producer producer;
public void bundleActivated(BundleContext con) {
this.producer.getNextItem();
}
}
Producer Bundle
package bundles.producer;
#Singleton
class Producer {
public String getNextItem() {
return "item x";
}
}
I want the OSGi runtime to start up the Consumer bundle, realize that it needs a Producer to work, the framework then starts the Producer bundle and injects and instance into the Consumer. Simples. iPOJOs suggest that this is possible using annotations only (#Singleton, #Inject) or similar, but I simply can't get it to work. OSGi apparently has declarative services, but that means writing a lot of XML, which I really want to avoid.
Anywoo, I'm prepared to adapt JBoss, Equinox or alternative OSGi runtime and an alternative dependancy injection mechanism, be that Peaberry, Spring DM or something completly difference. I'm already using Maven.
What I'm asking, is can somebody create a Hello World using the Producer and Consumer idea to help me get started? I've really spent a tonne of time reading up and find the learning curve insurmountable!
edit, my attempt using SCR: http://tydus.net/codeExamples/mvnScr.tar
It's better to use Declarative Service because it's a OSGi Standard.
You can use Java Annotations to describe DS dependencies, services and components with Maven SCR plugin
Regards,
Dmytro
There are two things to bear in mind; 1) your bundle will probably need some extra metadata for the dependency injection framework and 2) you'll need to deploy the DI framework's runtime.
Dependency injection is not part of core OSGi (i.e. the Felix framework) so you must first deploy the iPOJO bundle(s) before deploying your own. Additionally you'll need to add the metadata required by IPOJO, google "maven-ipojo-plugin" for more info.
If you're looking for a container that is less bare-bones than Felix on it's own, then try Karaf (it comes with lots of enterprise extras).
Personally, I like Declarative Services (so +1 Dmytro) as it's very simple and merely removes the boiler plate code from OSGi (remember to deploy it as well and provide component.xml in your bundle see maven-scr-plugin for more info).
EDIT
(In answer to comment and link to tarball below)
I moved the #Service annotation from Producer to ProducerImpl.
The generated SCR component.xml wasn't quite correct for the Consumer, by adding an unbind() method and changing the #Reference the following works:
//...
import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
import static org.apache.felix.scr.annotations.ReferencePolicy.DYNAMIC;
//...
#Component
public class Consumer
{
#Reference(policy = DYNAMIC, cardinality = MANDATORY_UNARY)
private Producer producer;
public void unbindProducer() {
System.out.println("Producer unbound.");
this.producer = null;
}
//...
}
Deploying Maven
As you're using maven, install Pax Url for maven, this way you can easily install bundles from local and remote repositories.
First get maven to download a version for you (pax-url-mvn version 1.3.5 is available) then install the file (or copy to Felix bundle dir)
-> install file:/YOUR_PATH_TO_MAVEN_REPO/.m2/repository/org/ops4j/pax/url/pax-url-mvn/1.3.5/pax-url-mvn-1.3.5.jar
Bundle ID: 7
-> start 7
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=javax.net.ssl) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=javax.xml.parsers) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.0.0)(!(version>=2.0.0))) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.service.cm)(version>=1.0.0)(!(version>=2.0.0))) -> [2.0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.service.url)(version>=1.0.0)(!(version>=2.0.0))) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=org.w3c.dom) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=org.xml.sax) -> [0]
->
You can now install your own bundles from your local repository with the mvn URL handler:
-> install mvn:com.examples/producer/1.0.1
Bundle ID: 10
-> start 10
-> install mvn:com.examples/consumer/1.0.1
Bundle ID: 11
-> start 11
DEBUG: WIRE: [11.0] osgi.wiring.package; (&(osgi.wiring.package=com.examples.producer)(version>=1.0.0)(!(version>=2.0.0))) -> [10.0]
Producer bound.
Consumer activate
Aloha.
->
I've written a fragment for the Equinox Declarative Services bundle that allows you to mark up your classes with annoations that correspond to DS servicce XML elements; yes, it's a hack with its own limitations, but it's working good so far in projects with 90+ bundles. I could probably manage to clean it up, document and publish it this week if you are interested.

Categories