As the title suggests, it turns out that using web services with Java is not as simple as you’d expect.
Executive Summary:
Axis 1.x is no good. I tested Axis2 and in many ways it’s worse. I tried XFire and it’s pretty good, but missing some functionality I needed. Finally, I moved to Sun’s JAX-WS RI (reference implementation), which turned out to be a good solution.
The process took way too long and involved way too much hacking.
And if you’re interested in the subject, here’s the complete story:
Apache Axis 1.x
There’s general agreement that Axis sucks. I’ve been a user since version 1.1, and I was never a happy user L . While it’s widely adopted, I decided to search for an alternative this time, especially since it looks like there isn’t much development effort going on in that project anymore, and Apache Axis2 is supposed to replace it.
Apache Axis2
If at all possible, Axis2 sucks even more than 1 did. The BileBlog sums it up better than I could. In short, I downloaded, played, read some docs, and decided to stay as far as I could. Next solution please.
Codehaus XFire
Now XFire’s a whole different story. Unlike Axis2 the code’s nicely written, and you don’t have to create aar’s out of your jar’s (and a host of other stupid inventions). It also integrates nicely with Spring, and so I managed to write a little test application in no time. Next I began using it with my main project code, and that’s where the problems started.
My data model includes a graph representation and I’ve some circular references between objects there, i.e. a parent referencing a set of children, and each child referencing the parent. It turns out that Aegis – the default XML binding engine for XFire doesn’t handle that situation well: when it serializes a child, it serializes the parent as well, which in turn serializes it’s own children (including the original child), and soon enough you get a StackOverflowError.
The obvious solution seemed to move to JAXB 2.0 which XFire supposedly supports. Unfortunately, it turns out that support isn’t good enough yet, and the WSDLs that I got from XFire using JAXB 2.0 and JSR 181 annotations weren’t readable by SoapUI.
App-Server-Specific Solutions
At this point I started looking at what JBoss and WebLogic are doing, since I heard that they had pretty good solutions of their own for Web Services. I really liked what I saw in WebLogic, but unfortunately one of my requirements for this project is to be app-server agnostic, so I decided not to go there just yet.
JAX-WS RI
In the end I came to Sun’s new open source reference implementation for the JAX-WS spec. I avoided it up until then, since a reference implementation usually does not bode well for scalability etc. Nevertheless, it seems that this time I struck gold!
First of all, exposing web services with JSR 181 annotations really is a breeze. Add Sun’s WSServlet dispatcher servlet to the web.xml and a simple sun-jaxws.xml file (finally, a simple xml configuration file!) to the WEB-INF directory, deploy the war to tomcat, and it just works.
I spent some more time on setting up JAXB 2.0 annotations on my data model classes, and the whole thing turned out just beautiful.
Next I wrote a web service client (since there’s no problem with my client being aware of the model and service packages, there was no point in generating from WSDL).
What took a little longer was building the thing with maven (dependency issues), but Mohan had provided a very helpful solution for that in his blog.
Next I tried to make JAX-WS RI play with Spring, which proved to be more difficult. Kohsuke Kawaguchi has a JAX-WS Commons project dedicated to integrating the two, but I couldn’t make the code work. Instead, I opted for a simpler solution – I load the Spring application context in a glue factory I wrote, rather than in the tomcat’s listener. My service classes call the factory to get Spring managed bean. It’s probably not “the Spring way”, but works for now – I might try Kohsuke’s solution again in the future.