I'm doing an experiment, developing an enterprise application in Java and Ruby in parallel, trying to evaluate whether Ruby is enterprise ready, or Java must still remain my weapon of choice.

Tuesday, January 09, 2007

Elad’s Adventures in Java WebServiceLand

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.


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.


Anonymous said...

Hi Elad-- I enjoyed your post, particularly because I've recently been through the very same excercise myself.

I really *wanted* XFire to be the answer, but similar issues as you mentioned kept me from being able to use it.

So far, the JAX-WS RI is working best for me as well. I've sent some comments to Kohsuke on problems with the current Spring integration-- hopefully it will be fixed soon!

In the back of my mind, though, I'm still hoping XFire will pull through in the end so I can move back to it.

Matt said...

Aegis can prevent your stack overflow issue. You just have to tell the child to ignore the parent. In your mappings for your child you do the following between the tags:

property name="parent" ignore="true"

Anonymous said...

Thanks for this post. I'm actually running into a similar situation with circular references and XFire (w/ Aegis or JAXB2). I would like to know if JAX-WS completely solves this circular reference issue (w/o the ignores hack) so that I can give it a shot.

Elad said...

Using JAX-WS with JAXB2 completely solved the circular reference issue for me.
The trick there is simply to map references as such with JAXB2.

sailie said...

Hi Elad,

Any update? Or you gave up Rails and went back to the Java land?

It will be great to let us know your final conclusion ...

Thanks in advance :-)

Anonymous said...

great post, looking forward to hearing the rest. I also have a 10 year java background, and am interested in knowing more about the rails hype.

I've heard a lot about rails being compared to Visual basic, i'd be interested in hearing more on the maintainability and what happens when you have to think out side of the "rails box".