A few months back I was working on a
REST based web service application using
CXF. CXF provides a cool
XML file out of box describing the methods available in the
REST interfaces. Since I was using
CXF I did not want
JBoss scanning my
REST interfaces and interfering with the classloader of my application. That's right class loader of the application (
WAR,
EAR). I'm taking a detour to explain what I meant there.
There's a hierarchy of classloaders in
JVM. In general if an application requires a class it asks it's classloader, this classloader asks it's parent classloader first. This way it's made sure that each class is uniquely available to entire JVM as the resolution is done by the parent classloaders first. It's an object hierarchy not a class hierarchy (not parent child, it's just a list). However, in case of
servlet containers or
JavaEE containers, applications try to load the class themselves first, instead of asking for parent first. This was done so that web application is run with the versions of the classess that were packed with it.
Reference :
Do You Really Get Class Loaders? A video from the
ZeroTurnaround, creators or
JRebel.
Coming back to the topic, since there were two different implementations of REST API (resteasy and CXF) available to my application, there was a conflict. No matter what I did, I could not get the JBoss to serve the WADL document. I was sure that this was happening because of the interference of Resteasy with the CXF.
I looked around and couldn't find the foolproof method. Most were asking to exclude Resteasy, JAXRS subsystems in
jboss-deployment-structure.xml file. Well I did that and that didn't work. I thought may be it couldn't solve my problem because I was trying to force solutions for the old JBoss version on the new one. However the problem runs deeper.
JBoss 6 has a maven like module system (just maven like, dependencies and all in "modules" directory). Every web application has a dependency on
JAVAEE module, which in turn loads
Resteasy and what not as dependency. (
modules/javaee/api/main/module.xml)
I could'nt exlude
JAVAEE module, or could I?
It turned out that I could actually exclude
JAVAEE entirely, and as
JAVAEE module itself is just a name for a collection of dependency modules, I could now load these modules selectively. Take a look at
modules/javaee/api/main/module.xml to see what dependencies are loaded by
JAVAEE module. If you try this method, it's guaranteed that this will cause less suffering and pain than any other method out there. Just start with everything(dependencies) excluded, except for the ones you know that no Java application can run without and start adding dependencies by taking the hint from the error that
JBoss gives you during the deployment.
I'm copying a sample
jboss-deployment-structure.xml file here. It should be packed
in the WEB-INF directory of the web application.
And yes, this solved my problem, finally I was able to get the
CXF provided
WADL document.
As you can see I have excluded parts which even remotely whisper web service.
Sample
WEB-INF/jboss-deployment-structure.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclude-subsystems>
<subsystem name="jaxrs" />
<subsystem name="webservices" />
<subsystem name="resteasy" />
</exclude-subsystems>
<exclusions>
<module name="javaee.api" />
<module name="javax.ws.rs.api" />
<module name="org.jboss.as.jaxrs" />
<module name="org.jboss.resteasy.resteasy-jaxrs" />
<module name="org.jboss.resteasy.resteasy-cdi" />
<module name="org.jboss.resteasy.jackson-provider" />
<module name="org.jboss.resteasy.resteasy-atom-provider" />
<module name="org.jboss.resteasy.resteasy-hibernatevalidator-provider" />
<module name="org.jboss.resteasy.resteasy-jaxb-provider" />
<module name="org.jboss.resteasy.resteasy-jettison-provider" />
<module name="org.jboss.resteasy.resteasy-jsapi" />
<module name="org.jboss.resteasy.resteasy-multipart-provider" />
<module name="org.jboss.resteasy.resteasy-yaml-provider" />
<module name="org.codehaus.jackson.jackson-core-asl" />
<module name="org.codehaus.jackson.jackson-jaxrs" />
<module name="org.codehaus.jackson.jackson-mapper-asl" />
<module name="org.codehaus.jackson.jackson-xc" />
<module name="org.codehaus.jettison" />
<module name="org.jboss.as.webservices.*" />
<module name="org.jboss.ws.*" />
</exclusions>
<dependencies>
<module name="javax.activation.api" export="true" />
<module name="javax.annotation.api" export="true" />
<!-- <module name="javax.ejb.api" export="true" />
<module name="javax.el.api" export="true" /> -->
<module name="javax.enterprise.api" export="true" />
<module name="javax.enterprise.deploy.api" export="true" />
<module name="javax.inject.api" export="true" />
<module name="javax.interceptor.api" export="true" />
<!-- <module name="javax.jms.api" export="true" />
<module name="javax.jws.api" export="true" />
<module name="javax.mail.api" export="true" />
<module name="javax.management.j2ee.api" export="true" /> -->
<module name="javax.persistence.api" export="true" />
<module name="javax.resource.api" export="true" />
<!-- <module name="javax.rmi.api" export="true" />
<module name="javax.security.auth.message.api" export="true" />
<module name="javax.security.jacc.api" export="true" /> -->
<module name="javax.servlet.api" export="true" />
<module name="javax.servlet.jsp.api" export="true" />
<module name="javax.transaction.api" export="true" />
<module name="javax.validation.api" export="true" />
<!-- <module name="javax.ws.rs.api" export="true" services="export" /> -->
<module name="javax.xml.bind.api" export="true" />
<module name="javax.xml.registry.api" export="true" />
<module name="javax.xml.soap.api" export="true" />
<module name="javax.xml.ws.api" export="true" />
<!-- This one always goes last. -->
<module name="javax.api" export="true" />
</dependencies>
</deployment>
</jboss-deployment-structure>
In this application I was loading my own Jackson library, so that's also excluded.
...till next time