We're updating the issue view to help you get more done. 

Upgrade to JAXB 2.3

Description

Currently we're depending on JAXB 2.2.11, which works with both Java 8 and 11, and (critically) is the version included in Karaf, so it also works in Karaf.

However, this is not the latest version, and we will need to upgrade the dependency, first in order to remove any recently fixed security vulnerability, but also to make it easier for users to integrate with other libraries that use JAXB (possibly a newer version of it).

The problem is, it is not currently possible to use the latest version, JAXB 2.3.1, within Karaf. There are multiple reasons:

  1. Several dependencies of Karaf's declare in their OSGi metadata that they require Java 9+. This includes in particular stax-ex 1.8 and FastInfoset 1.2.15, maybe others. If we upgrade, and install these dependencies in a Karaf instance, Karaf just will fail on startup with Java 8 because of unsatisfied dependencies. Dependencies will be satisfied when running it with Java 11, though...

  2. Even if we can solve the above, I am not sure that it's possible to use our own JAXB bundle in Karaf. So far we've always use the JAXB bundle provided by the JRE (when using Java 8) or Karaf (when using Java 11 in particular). And when I try to add our own version of JAXB to Karaf, I'm unable to make it all work.

I started a sandbox project to help experiment with the upgrade, and if necessary allow us to provide reproducers to the Karaf team: https://github.com/yrodiere/karaf-sandbox

So far I only tested a "naive" approach where I wrap the JAXB JARs as OSGi bundles, put them in the Karaf instance, and see how it goes. There are other approaches, though. See this PR for details, in particular this section:

The second issue is that JAXB JARs do not work "out of the box". Just adding the runtime JAR as a bundle to our feature is not enough, the API classes will not detect it. Apparently it's because the JAXB JARs do not declare service implementations as OSGi requires (using blueprints, for example). Here are the solutions I could think of:

  • Use com.sun.xml.bind:jaxb-osgi, which is an OSGi bundle by the JAXB maintainers. Looks ideal? No it's not:

    • This bundle includes jaxb-xfc, which requires a lot of dependencies, among which package com.sun.source.tree which is part of the Java compiler APIs and is not available by default in Karaf (I couldn't find the appropriate OSGi bundle).

    • I'm not even sure this OSGi bundle will work correctly if we solve the problem above, because the source code for this Maven artifact doesn't look like it does anything special to declare service implementations (no blueprints in particular). Maybe it will, but given the strange stuff we do in our classloader, I wouldn't bet on it.

  • Wrap the JAXB JARs ourselves, adding whatever OSGi configuration that is necessary.

    • Maybe we could create a clean bundle with all the correct configuration, but that would essentially mean re-building the jaxb-osgi artifact ourselves.

    • [This was true before that PR, this may be obsolete]I was able to come up with a very simple wrapping. It's an ugly and probably fragile hack, but it works in Karaf with both JRE 8 and JRE 11. The hack consists in wrapping the JAXB runtime bundle, adding in particular an "Export-Package: META-INF.services" instruction to the manifest. Due to how resource loading works in Karaf, this ends up exposing the relevant META-INF/services/XXX file from the runtime bundle to the API classes, and the API classes end up instantiating the runtime as we would expect.

Here are the stack traces I got:

Java 8:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 org.apache.felix.resolver.reason.ReasonException: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=karafsandbox-core; type=karaf.feature; version="[1.0.0.SNAPSHOT,1.0.0.SNAPSHOT]"; filter:="(&(osgi.identity=karafsandbox-core)(type=karaf.feature)(version>=1.0.0.SNAPSHOT)(version<=1.0.0.SNAPSHOT))" [caused by: Unable to resolve karafsandbox-core/1.0.0.SNAPSHOT: missing requirement [karafsandbox-core/1.0.0.SNAPSHOT] osgi.identity; osgi.identity=karafsandbox-jaxb; type=karaf.feature; version="[1.0.0.SNAPSHOT,1.0.0.SNAPSHOT]" [caused by: Unable to resolve karafsandbox-jaxb/1.0.0.SNAPSHOT: missing requirement [karafsandbox-jaxb/1.0.0.SNAPSHOT] osgi.identity; osgi.identity=org.jvnet.staxex.stax-ex; type=osgi.bundle; version="[1.8.0,1.8.0]"; resolution:=mandatory [caused by: Unable to resolve org.jvnet.staxex.stax-ex/1.8.0: missing requirement [org.jvnet.staxex.stax-ex/1.8.0] osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=9.0))"]]] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] at org.apache.felix.resolver.ResolverImpl.doResolve(ResolverImpl.java:392) ~[?:?] at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:378) ~[?:?] at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:332) ~[?:?] at org.apache.karaf.features.internal.region.SubsystemResolver.resolve(SubsystemResolver.java:257) ~[?:?] at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:388) ~[?:?] at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1025) ~[?:?] at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:964) ~[?:?] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:?] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?] at java.lang.Thread.run(Thread.java:748) [?:?] Caused by: org.apache.felix.resolver.reason.ReasonException: Unable to resolve karafsandbox-core/1.0.0.SNAPSHOT: missing requirement [karafsandbox-core/1.0.0.SNAPSHOT] osgi.identity; osgi.identity=karafsandbox-jaxb; type=karaf.feature; version="[1.0.0.SNAPSHOT,1.0.0.SNAPSHOT]" [caused by: Unable to resolve karafsandbox-jaxb/1.0.0.SNAPSHOT: missing requirement [karafsandbox-jaxb/1.0.0.SNAPSHOT] osgi.identity; osgi.identity=org.jvnet.staxex.stax-ex; type=osgi.bundle; version="[1.8.0,1.8.0]"; resolution:=mandatory [caused by: Unable to resolve org.jvnet.staxex.stax-ex/1.8.0: missing requirement [org.jvnet.staxex.stax-ex/1.8.0] osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=9.0))"]] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] ... 12 more Caused by: org.apache.felix.resolver.reason.ReasonException: Unable to resolve karafsandbox-jaxb/1.0.0.SNAPSHOT: missing requirement [karafsandbox-jaxb/1.0.0.SNAPSHOT] osgi.identity; osgi.identity=org.jvnet.staxex.stax-ex; type=osgi.bundle; version="[1.8.0,1.8.0]"; resolution:=mandatory [caused by: Unable to resolve org.jvnet.staxex.stax-ex/1.8.0: missing requirement [org.jvnet.staxex.stax-ex/1.8.0] osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=9.0))"] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] ... 12 more Caused by: org.apache.felix.resolver.reason.ReasonException: Unable to resolve org.jvnet.staxex.stax-ex/1.8.0: missing requirement [org.jvnet.staxex.stax-ex/1.8.0] osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=9.0))" at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343) ~[?:?] ... 12 more

Java 11:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory not found by org.ops4j.pax.exam.rbc [65] at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1639) at org.apache.felix.framework.BundleWiringImpl.access$200(BundleWiringImpl.java:80) at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2053) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122) at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276) at javax.xml.bind.ContextFinder.find(ContextFinder.java:421) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) at org.hibernate.karafsandbox.core.internal.configuration.LibraryConfigurationLoader.<init>(LibraryConfigurationLoader.java:23) at org.hibernate.karafsandbox.core.LibraryBootstrapper.bootstrap(LibraryBootstrapper.java:22) at org.hibernate.karafsandbox.osgi.OsgiIntegration.bootstrapWithOsgiClassLoader(OsgiIntegration.java:32) at org.hibernate.karafsandbox.osgi.testpackage.OsgiIntegrationTest.testWithOsgiClassLoader(OsgiIntegrationTest.java:152) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runLeafWithRetry(ContainerTestRunner.java:97) at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChildWithRetry(ContainerTestRunner.java:84) at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:75) at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:43) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.invokeViaJUnit(JUnitProbeInvoker.java:124) at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.findAndInvoke(JUnitProbeInvoker.java:97) at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.call(JUnitProbeInvoker.java:73) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.ops4j.pax.exam.rbc.internal.RemoteBundleContextImpl.remoteCall(RemoteBundleContextImpl.java:85) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359) at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)

Environment

None

Status

Assignee

Yoann Rodière

Reporter

Yoann Rodière

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

backportDecision

None

Components

Priority

Major