Redeemed! JAX-WS still sucks!
Recap of the JAX-WS Debate
You may not have been following the thread of discussion about JAX-WS between Jason Greene and myself, so I'll provide a recap. On March 23rd I posted a blog entry intitled "JAX-WS is Bad, Bad!" the point of which was that JAX-WS is a small improvement over JAX-RPC (see "JAX-RPC is Bad, Bad, Bad!") but is still way too complicated. In that post I issued a challenge to the JAX-WS team to show me that it's easy to implement web services for eBay and Amazon.com using JAX-WS 2.0. Jason Green, the JBoss developer who is working on the JBoss implementation of JAX-WS posted what appeared to be a very simple solution. While he had created a client application and not a service, I decided that he had in fact met the technical requirments of the challenge and so, as promised, I eat my own words as reported in this posting "Eating My Own Words". However, in that posting I clarified the challenge to specify that the eBay and Amazon.com should implemented as web services, rather than clients (I left out the bit about eating my own words because I still wasn't feeling well from the first dead-tree breakfast).
Challenging the challenge to my challenge
Soon after my last post, Jason Greene seemed to have answered the challenge again with this post "Taking RMH's JAX-WS Challenge". It appeared that I had been outdone by the Wily Jason Greene once again. At this point I decided that I needed to try and implement these web services myself. I had taken a hard stance about JAX-WS and if I was wrong, as Jason Greene's examples suggested, I would need to make amends. A public apology and a full retraction.
So yesterday I contacted Jason and requested that he work with me to implement these solutions so I could see first hand the ease with which they are implemented. Jason was extreemly gracious and helpful. Jason provided me with a pre-packaged solution for the Java Web Service Reference Implementation and some addition instructions for how to deploy it. Although I was very grateful that he had taken the time to package up a solution, I wanted to create my own web services from scratch. Jason was more than happy to help, but I needed sometime to set up accounts. I never did get back in contact with Jason. What I discovered between then and now made it unnecessary.
For several hours yesturday I attempted to create web service clients, surely the simplest of endpoints, to connect to Amazon.com, eBay.com, Google, and a couple other web services provided by Atomic-X.com. Rather than use the Web Services Reference API I decided to use the Java EE 5 reference API which I already had installed the previous day and understood well enough to make quick progress. Or so I thought. All I wanted to do, as a first step, was create a web service client for eBay or Amazon.com but try as I might I never succeeded.
At first I tried the Amazon.com web services. I wanted something really simple so I chose an operation that returns the sales rank of a book given its ISBN number. I downloaded the WSDL and used the JAX-WS utility (i.e. wsimport) to generate the package I would use to access the web service. Than I examined the WSDL document and using Jason's eBay example as a general guide attempted to implement the web service client. I never got it working. Although I figured out how to set some of the values being passed to the service, I couldn't figure out how to set all of them. I referenced this web site that Amazon.com provides so that I could see what the outgoing and incoming data would look like (funny but yesterday it showed me the actual SOAP requests, but today it shows me raw data) so I knew that the service actually works and what I might expect in terms of outgoing and incoming messages. After mucking around with it for a couple of hours I gave up. I must have chosen too complex of service to start out with. I decided to try something simpler.
Next I tried a couple web services from Atomic-X, which provides publicly available and really simple web services. I had to give up on this one too because the wsimport utility provided by the JAX-WS 2.0 RI kept throwing errors when I tried to generate the JAX-WS package to access the services. It said it didn't recognize the s:schema tags. Hmm ... well I'll try Google, I thought. They have a web service.
I decided to try the web service operation that lets you check the spelling of a word, it was pretty simple. Unfortunately, I couldn't get the wsimport utility to work on that web service either because it uses SOAP Encoded messages and wsimport doesn't seem to support that. Ok, that's understandable. Everyone knows that SOAP Encoding is a bad idea anyway (Hey Google guys! What's up with that?)
Having tried three public web services with no success I decided to see if I could at least generate the JAX-WS package for the eBay web services. That worked like a charm, but something bothered me. The eBay package contains hundreds of classes. That led me to investigate the WSDL/JAX-WS bindings generated by the wsimport tool and to my final conclusions that JAX-WS sucks.
Looking at the eBay WSDL and Jason's example it was pretty easy to tell that you start with the Java class that represents the wsdl:service. It's a factory from which you access port types that are essentially interfaces to the web service. Still, I thought, how would I have understood that if (a) I didn't already have a deep understanding of WSDL 1.1 and (b)I had not seen Jason's example? Also, why were there so many classes? They seemed to go on forever.
Well one explanation for all the classes was that the eBay WSDL itself was enormous. But when I looked at the Amazon.com package generated by JAX-WS it too was quite large, yet the Amazon.com WSDL seemed reasonable in size. How many classes were there and how did they compare to the WSDL? Time to start counting.
In the end I was thunderstruck by the number of classes that JAX-WS generated for both eBay and Amazon.com (the only web services I was able to generate classes for).
eBay requires 700 + Java classes
For example, the eBay WSDL includes a whopping 500 XML Complex Schema types, 200 WSDL message types, and 1 port type. That's ridiculous, but it might account for the huge package of Java classes that was generated by the JAX-WS wsimport tool. When I counted the Java source files generated from the WSDL I came up with over 700 Java classes! Maybe there is a Java class for each XML Schema type and WSDL message type? Still that seemed weird. Why would it be the sum of those and not simply be equal to the XML Complex Schema types and a couple of ancillary classes.
Amazon.com requires 124 Java classes
Next I did the same inspection of the Amazon.com WSDL and generated JAX-WS classes. The Amazon.com WSDL defines 18 XML Complex Schema types, 40 WSDL message types, and 1 port type. However, the JAX-WS generated 124 Java classes! That seemed really weird! Why so many classes? I could see 42 or 43 classes (one for each complex type plus classes representing services and port types), but 124?
The Hands Go Up
After making those counts and trying to reconcile the Java classes to WSDL documents, I threw my hands in the air. This was just way too complicated! JAX-WS was not making things simpler, any more than JAX-RPC! For every web service I wanted to use, I had to deal with an entirely new API represented by the JAX-WS packaged generated from the WSDL document. Not only that, but the generated classes were not documented! There was no tutorial that showed me how to use them and despite claims to the contrary, it wasn't self evident.
If you know WSDL (and I do) and you can study the source code closely (which I did) you could kind-of figure out how to use each new web service API. But, that's a lot of work. Too much work if you ask me. It made me understand why Google, eBay, and Amazom.com all provided their own proprietary toolkits for Java, C and C#: These web services were complex and demanded not only a straightforward API but plenty of documentation to back them up. With JAX-WS you get neither of those things.
The web service API (package) generated by JAX-WS is not straightforward unless you already have expertise in WSDL as well as other skills I'm probably taking for granted. In addition, the JAX-WS APIs being generated are not documented. The JAX-WS tools could never create a tutorial in addition to the APIs. That would require human intervention. In other words, in order for the JAX-WS to be useful when dealing with complex web services you would have to generate the classes and then write your own documentation, otherwise everyone in your organization would have to re-invent the cognitive wheel that probably took you days to grok.
This experience trying to use JAX-WS has led me to believe, more firmly than before, that JAX-WS is a crazy, awful, terrible mess of a solution for Java web services. Something much simpler is required. Think of this, I spent 18 months researching and writing a book on J2EE web services. I delved deeply into the XML, SOAP, WSLD, UDDI, JAX-RPC, SAAJ, JAXR, and JAXP APIs. With all that background you would think it would be easy, but in fact I made no progress whatsoever. How are developers who do not have the benefit of all that training supposed to use JAX-WS? Jason Greene may find it easy to create short programs for accessing and hosting web services with JAX-WS, but than again the guy is implementing the specification for JBoss. No duh! Of course its going to be easy for him to come up with a seemingly simple program. Now you try it. Just make sure you have plenty of time to waste figuring out what I did. JAX-WS sucks. There: I said it again.
Having said all that, let me take a minute to defend Jason and his co-horts in the JAX-WS specification team. I think given the objective of JAX-WS, which is to provide a comprehensive mapping between WSDL web services and Java, they have done a fine job. As I've said, JAX-WS is somewhat simpler than JAX-RPC. The problem is not with the engineering its the objective. Why are they trying to create an RPC binding for web services? Hey guys, you may have taken the RPC out of the name, but you didn't take the RPC out of the technology. JAX-WS is an inherently flawed model. Rather than simplify SOAP/WSDL based web services, they made them much more complicated. What is needed is not a better RPC style web services API, what is needed is a completely different approach.
There is a better way to do this and that's by working with web services as XML messages and not remote objects or procedures. The solution, I believe, is to scrap JAX-WS 2.0 and start over with a completely different programming model. One based on the use of native XML types in Java. Something similar E4X (ECMAScript for XML). But that is the subject of another post.
I have no illusions that JAX-WS will be scrapped in favor of something completely different. Not yet anyway; not until the masses have suffered enough to drive them to other solutions. Only then, will it become clear to the Java EE vendors (including JBoss) that JAX-WS and its ilk are, and always have been, the wrong approach to consuming and producing web service messages.