JBoss Fuse – Deploying JAX-RS services with Fuse 6.2 and Java 8

Depending on the parts of CXF your JAX-RS services utilise, you might have a little OSGi-wrangling on your hands if you want to deploy them to JBoss Fuse 6.2 on Java 1.8

The latest and recently released 6.2 version of JBoss Fuse supports both Java 1.8 and CXF 3.0, and for anyone working on a service that targets this platform and which hasn’t yet hit production, taking the upgrade now is likely to be tempting; both to leverage new features and to avoid having to migrate live services later.

Since the latest and recently released 6.2 version of JBoss Fuse supports both Java 1.8 and CXF 3.0, upgrading a JAX-RS service ought to be a simple matter of changing some versions in your POM files, fixing any deprecated CXF features you’ve been clinging to for too long, and dropping your fresh bundle into the server.

And you might well get lucky.

But if you’re using JAX-RS filters, probably not.

Annotation Agitation

If you’ve got any ContainerRequestFilter or ContainerResponseFilter classes in your JAX-RS provider chain, and you’re deploying on a Java 1.8 runtime, you’re likely to see a stack trace like this when your service tries to start:-

Exception in thread "SpringOsgiExtenderThread-10" 
  org.springframework.beans.factory.BeanCreationException: 
  Error creating bean with name 'cxfTimeService': 
  Invocation of init method failed; nested exception is 
  java.lang.NoClassDefFoundError: javax/annotation/Priority
    at org.springframework.beans.factory.support.
       AbstractAutowireCapableBeanFactory.initializeBean(
       AbstractAutowireCapableBeanFactory.java:1514)
    …
Caused by: java.lang.NoClassDefFoundError: javax/annotation/Priority
    at org.apache.cxf.jaxrs.utils.AnnotationUtils.
       getBindingPriority(AnnotationUtils.java:85)
    at org.apache.cxf.jaxrs.provider.ProviderFactory.
       getFilterPriority(ProviderFactory.java:1172)
    …
Caused by: java.lang.ClassNotFoundException: javax.annotation.Priority
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    …

What’s particularly interesting about this stack trace is that it’s a plain, old ClassNotFoundException at the root. We’re in an OSGi environment after all – if we’ve got missing dependencies then surely we should be seeing wiring exceptions instead?

Checking out the extremely helpful OSGi tab in Fuse’s Hawtio console shows us that the JAX-RS CXF Frontend wants version 1.2 of javax.annotations and has indeed been given it:-

Fuse CXF bundle wiring on Java 1.8

So what’s providing it? A quick look at the Packages page reveals the answer – it’s bundle 0 – the container itself:-

Fuse java.annotation package provision on Java 1.8

So, CXF 3.0’s JAX-RS front-end requires version 1.2 of the javax.annotations package (specifically in this case, the Priority annotation). Fuse on Java 1.8 is providing this package from the JVM, but the JVM doesn’t have that class in it. This all rather suggests to me that JDK 1.8 doesn’t have version 1.2 of the javax.annotations package at all. It looks distinctly like 1.1 to me.

Since out-of-the-box Fuse 6.2 is providing this package from the JVM, overriding it with the same bundle CXF would wire up to on Java 1.7 isn’t completely straightforward.

Since this is OSGi though there are plenty of opportunities to work around it.

Here are a couple of suggestions.

Annotation Fabrication

Fuse supplies version 1.2 of this package from the JVM because the file /etc/jre.properties says that JDK 1.8 provides it:-

jre-1.8= \
  javax.accessibility, \
  javax.activation;version="1.1", \
  javax.activity, \
  javax.annotation;version="1.2", \
  javax.annotation.processing;version="1.2", \
  …

And indeed, changing this to 1.1…

  javax.activation;version="1.1", \
  javax.annotation.processing;version="1.1", \

…and bouncing the container is enough to make the service wire up to the mvn:javax.annotation/javax.annotation-api/1.2 Maven bundle and start successfully.

Annotation Subjugation

The above solution is pretty painless for straightforward Fuse deployments and even if you’re using Fabric SSH containers, since Fuse 6.2 zips itself up to provide the container runtime when first requested, remote containers should get the change automatically too (you might need to delete the current version of the ZIP under the system/ folder if you’ve created SSH containers already in order to get a fresh copy built).

If you’ve got complex deployment requirements though and don’t want to rely on corrections to multiple copies of this file you might prefer an OSGi-only solution. Sadly my OSGi wrangling skills don’t extend to forcing the wiring for third party bundles, nor overriding JVM provided classes, but if you’re happy with a slightly hacky workaround, read on.

Since CXF wants to wire up to a version of javax.annotation equal to or greater than 1.2, exporting the contents of the 1.2 Annotations API bundle as, say, version 1.2.1 will do the trick (though not something you’d want to forget having done!)

If you’re using the Apache Felix bundle plugin it’s pretty easy to create a JAR file which re-exports a dependency with “tweaked” properties:-

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0     
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.devsumo.examples.fuse</groupId>
    <artifactId>osgi-dependencies</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>
    <name>Additional OSGi dependencies</name>
    <description>Bundle for modified/non-OSGi dependencies</description>

    <dependencies>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.3.7</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                       
                           artifactId=javax.annotation-api;inline=true
                       </Embed-Dependency>
                       <Export-Package>
                           javax.annotation.*;version=1.2.1
                       </Export-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Here we’re simply creating an OSGi bundle with a single dependency – version 1.2 of the Java Annotations API – and using Felix to export this dependency but as version 1.2.1 instead.

This bundle will need an OSGi start level lower than that of the other CXF bundles (40). I can’t think why you’d want to take this approach with a standalone Fuse instance but you can use the osgi:bundle-level command to do this in the Karaf console:-

osgi:bundle-level <bundle-id> 30

If (more likely with this approach) you have an OSGi features XML associated with your bundles, including this bundle as a feature and setting the start-level property to a sufficiently low value will do the trick:-

<features name="time-service-feature">
    <feature name="osgi-dependencies-feature" start-level="30">
        <bundle>…</bundle>
   <feature>
   …
</features>

Leave a Reply

Your email address will not be published. Required fields are marked *