I recently used Spring-WS in an application that we wanted to deploy under JBoss 4.0.1sp1 / JDK 1.5 and JBoss 5.1.0GA / JDK 1.6. I had a good few problems getting the dependencies just right but the biggest problem was with SAAJ.
If you’re running JBoss 4.0.1sp1 and JDK 1.5, you’ll need to package a SAAJ implementation with your app. Easy enough. However, if you’re running JBoss 5.1.0GA and JDK1.6, you don’t want to include a SAAJ implementation as it’s included in the JDK 1.6 release. Also easy enough? Er no.
Jboss 5.1.0GA (the JDK 1.6 distribution anyway) also has an implementation of SAAJ (jbossws-native-saaj.jar). And it uses the endorsed standards mechanism (the jar is in the lib/endorsed directory) to override the Sun reference implementation. Unfortunately it’s broken. And the JBoss 5.x branch is no longer supported so it’s not likely to get fixed. I found when I tried to use this that all my SOAP responses were empty. I think that counts as a critical bug for a SOAP service.
If you want to make Spring-WS work against multiple JDK / JBoss environments, you may need to create multiple distributions to deal with the idiosyncrasies of each environment.
Fix 1 – include SAAJ for JDK 1.5 builds only
Maven 2 (ain’t it great!) solves this one quite neatly. You can create two build distributions and control them with profiles. Say your ‘standard’ dependency management config assumes that SAAJ is provided (with JDK 1.6):
<dependencyManagement> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.xml.soap</groupId> <artifactId>saaj-api</artifactId> <version>1.3</version> <scope>provided</scope> </dependency> </dependencyManagement>
Then you can create a ‘special’ JDK1.5 profile to build the version with SAAJ included like this:
<profiles> <profile> <id>jdk15</id> <dependencyManagement> <dependencies> <dependency> <groupId>javax.xml.soap</groupId> <artifactId>saaj-api</artifactId> <version>1.3</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.3</version> <scope>compile</scope> </dependency> </dependencies> </dependencyManagement> </profile>
If you build with profile ‘jdk15’ activated, the SAAJ jars get built into your app. The profile is activated like this:
mvn package -Pjdk15
Fix 2 – Avoid broken JBoss 5.1.0 SAAJ
There’s a standard solution to this problem that I found after a bit of Googling:
http://static.springsource.org/spring-ws/sites/1.5/faq.html#saaj-jboss
http://community.jboss.org/thread/150157
However, this solution would not be compatible with a JBoss 4.0.1sp1 setup as that SAAJ implementation would not be there. If you want to use this solution only in a JBoss 5.1.0 setup and disable it when it’s deployed under JBoss 4.0.1, you’ll need to get sneaky.
Put the suggested hack into its own spring config file called spring-ws-servlet-jdk50.0.xml. It just looks like this:
<beans> <!-- Big magic hack to fix the broken SAAJ in JBoss See http://static.springsource.org/spring-ws/sites/1.5/faq.html#saaj-jboss --> <bean id="messageFactory"> <property name="messageFactory"> <bean class="com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl"/> <bean/> </beans>
Also create a corresponding file called spring-ws-servlet-jdk49.0.xml. It’s just an empty bean definition file. Then in the main spring-ws-servlet.xml file, make sure you import the version specific one:
<beans> <import resource="spring-ws-servlet-jdk${java.class.version}.xml"/> <bean/> ...
This demonstrates a nice little way to hack conditional logic into Spring config. Spring has no if statements, but if you really need them, you can do this trick with file imports. Not ideal, but it can get you out of a spot.
This is not quite a complete solution. It assumes that you can work out which JBoss version you’re using from the JDK version. In my environment we can – if it’s JDK 1.5 then it’s JBoss 4.0.1, otherwise it’s JBoss 5.1.0. If you can’t make this assumption you could just use some other system property instead of java.class.version.
[…] conflicting with each other. I've noted a couple of these conflicts in a previous post regarding SAAJ in JBoss 5 but it's likely that some serious Googling may be required for your particular setup. I've included […]
Thanks, your post really helped me, I was already panicking 😉
Thanks for your post. It helped me to fix the same issue with springws-jboss.
This is a nice explanation. Thanks for taking the time to write it up.
Thanks for writing this up. Helpful. I also had to include saaj-api and saaj-impl libraries in my WAR file to prevent the class not found exception. Not sure why jboss 5.1 couldn’t pick up the jdk1.6’s SAAJ impl class by itself.