I've written before with Ted Neward on code-first vs WSDL-first contract design for services. We had a lot of fun on the Server Side with that - thanks Ted (and the men in black).
Since then, I've mellowed a lot; I'm quite happy to use JAX-B and JAX-WS annotations where appropriate to generate my WSDL and XSD SOA artifacts. Maybe Ted's mantra of "Code first, contract aware" has rubbed off on me.
Recently thought I've noticed another approach, JiBX, that offers a middle ground. Instead of embedding annotations inside your Java classes (code-first), or writing your own schema (contract first), you put XML binding information into a separate "binding" file. You then run a tool against the Java classes and binding file and out drops the schema.
I look forward to playing with JiBX, but I can't help but feel cautious. One of the compelling reasons to use a code first approach is the idea that it's somewhat simpler than writing XSD or WSDL by hand. JiBX just doesn't look "easy" to me; it seems that if you want to you use JiBX then you need to know about your Java interfaces, your desired schema/XML, and, how to use JIB-X binding files. So, we end up having to learn new stuff (JiBX) to do things we can do already (XML Schema).
I think what I'm lacking is the presence of a "JiBX in Anger" article (remember Ant in Anger?) that shows how JiBX solves the Java/XML problem way better than the approaches I know already. From my own recent experience with the CXF java2wsdl tool (see the previous entry on this blog), I know that JiBX would give me explicit control over how XSD artifacts get generated from pre-JDK 1.5 annotation-free classes. Very nice - but worth the overhead of learning JiBX?
Monday, September 3, 2007
Friday, August 31, 2007
Code first mayhem: generating WSDL from EJB interfaces
I'm working on a project that involves writing stubs for EJB services. Our approach is to write a simple EJB that delegates to a web service (stub "intelligence" lies in the web service).
Obviously, we want the web service to conform to the same API as the original EJB interface: same methods, same parameter lists, etc. So, I'm using the Artix java2wsdl tool to generate corresponding WSDL artifacts (and associated XSD) from the EJB interfaces. This tool is based on Apache CXF java2wsdl, which in turn is based on the reference implementation of JAX-B.
Now, you'd think that this should be a cinch: however, I ran into a number of difficulties and had to some up with some crafty workarounds. The bottom line is that generating contracts from raw code is trickier that you might expect. Read on for your pleasure...
First Problem: Naming Conflicts. The EJB interface uses types that create naming conflicts with wrapped-doc-literal artifacts.
Who would have thought it? The EJB interface used a wrapping style that conflicted with the naming conventions for wrapped-doc-literal. The EJBs had APIs that looked like this:
void sayHello(String s, SayHello params),
java2wsdl will try and create a schema definition for SayHello (the type in the parameter list). The tool will then try and create a wrapper XSD element for the sayHello message, also called SayHello. Ouch... naming collision here we come.
To get around this, I took advantage of the fact that SayHello (the parameter type) was actually in a different Java package: I just needed to map the Java package to a different schema namespace. This is tricky though: the only way to do this in JAX-B is to annotate the source: I only had access to the class files. I posted the problem to the cxf-dev mailing list, you can read more on the problem there. The solution was to artificially recreate the EJB package structure, inserting package-info.java classes to control the mapping. Then, by placing this hierarchy in front of the EJB jars in the classpath, we were able to take control of the mapping as if the annotations had been their all along. Tricky, but fun: in the end we decided this was "Artful Hackery".
Second problem: public fields clash with set/get methods.
Some of the data types used by EJB had a public member (say foo) along with a getFoo() method:
class MyDataType {
public int foo;
public int getFoo();
}
Alarmingly, the java2wsdl compiler complained that there were "two members with the same name." Double ouch. It turns out that to fix this problem, I had to add some smarts to the package-info.java file I created to front the package containing the data types, setting the XmlAccessorType to be FIELD.
Something like this:
@javax.xml.bind.annotation.XmlAccessorType(
javax.xml.bind.annotation.XmlAccessType.FIELD
)
Third problem: beans need to have a no-argument constructor. One of the data-types used in an interface didn't have a default no-argument constructor. This was enough to stop the java2wsdl compiler in its tracks. I couldn't find a JAX-B workaround for this; also I don't know of a way to inject a no-argument constructor into an existing class.
So: hurrah for Java decompilers: I decompiled the offending class, added a constructor, recompiled it and placed it in the CLASSPATH ahead of the Jar so that it would be picked up first.
Phew. "Apart from that, it all went swimmingly".
Obviously, we want the web service to conform to the same API as the original EJB interface: same methods, same parameter lists, etc. So, I'm using the Artix java2wsdl tool to generate corresponding WSDL artifacts (and associated XSD) from the EJB interfaces. This tool is based on Apache CXF java2wsdl, which in turn is based on the reference implementation of JAX-B.
Now, you'd think that this should be a cinch: however, I ran into a number of difficulties and had to some up with some crafty workarounds. The bottom line is that generating contracts from raw code is trickier that you might expect. Read on for your pleasure...
First Problem: Naming Conflicts. The EJB interface uses types that create naming conflicts with wrapped-doc-literal artifacts.
Who would have thought it? The EJB interface used a wrapping style that conflicted with the naming conventions for wrapped-doc-literal. The EJBs had APIs that looked like this:
void sayHello(String s, SayHello params),
java2wsdl will try and create a schema definition for SayHello (the type in the parameter list). The tool will then try and create a wrapper XSD element for the sayHello message, also called SayHello. Ouch... naming collision here we come.
To get around this, I took advantage of the fact that SayHello (the parameter type) was actually in a different Java package: I just needed to map the Java package to a different schema namespace. This is tricky though: the only way to do this in JAX-B is to annotate the source: I only had access to the class files. I posted the problem to the cxf-dev mailing list, you can read more on the problem there. The solution was to artificially recreate the EJB package structure, inserting package-info.java classes to control the mapping. Then, by placing this hierarchy in front of the EJB jars in the classpath, we were able to take control of the mapping as if the annotations had been their all along. Tricky, but fun: in the end we decided this was "Artful Hackery".
Second problem: public fields clash with set/get methods.
Some of the data types used by EJB had a public member (say foo) along with a getFoo() method:
class MyDataType {
public int foo;
public int getFoo();
}
Alarmingly, the java2wsdl compiler complained that there were "two members with the same name." Double ouch. It turns out that to fix this problem, I had to add some smarts to the package-info.java file I created to front the package containing the data types, setting the XmlAccessorType to be FIELD.
Something like this:
@javax.xml.bind.annotation.XmlAccessorType(
javax.xml.bind.annotation.XmlAccessType.FIELD
)
Third problem: beans need to have a no-argument constructor. One of the data-types used in an interface didn't have a default no-argument constructor. This was enough to stop the java2wsdl compiler in its tracks. I couldn't find a JAX-B workaround for this; also I don't know of a way to inject a no-argument constructor into an existing class.
So: hurrah for Java decompilers: I decompiled the offending class, added a constructor, recompiled it and placed it in the CLASSPATH ahead of the Jar so that it would be picked up first.
Phew. "Apart from that, it all went swimmingly".
And who are you, exactly?
My name is Ade, and I work for IONA Technologies as a Principal Consultant in their Services Organisation. As part of my role I get to travel a lot, meet customers, and design and build software solutions using a pretty wide range of middleware technologies: Web Services, CORBA, J2EE, JMS, open-source, closed source - all the usual suspects are there. I love my job - it's a great way to meet people and learn a whole lot of stuff.
I've been blogging for a while on the IONA SOS blog (see sidebar for a link); I've also been getting lots of great opportunities to speak around Europe on SOA and on middleware.
In this blog I'm going to share my middleware experiences - from the sublime to the ridiculous - and talk about my perspectives on architecting and implementing distributed systems.
While I do have an academic background, it's not actually in distributed systems (although it was a whole lot of fun building a networked supercomputer out of the Maynooth software labs to run my Ph.D. experiments in genetic programming)... It turns out there's a lot your can do with 200 PCs and a shared file system ;)
Anyway - welcome. I hope you find the articles on this blog interesting and helpful.
I've been blogging for a while on the IONA SOS blog (see sidebar for a link); I've also been getting lots of great opportunities to speak around Europe on SOA and on middleware.
In this blog I'm going to share my middleware experiences - from the sublime to the ridiculous - and talk about my perspectives on architecting and implementing distributed systems.
While I do have an academic background, it's not actually in distributed systems (although it was a whole lot of fun building a networked supercomputer out of the Maynooth software labs to run my Ph.D. experiments in genetic programming)... It turns out there's a lot your can do with 200 PCs and a shared file system ;)
Anyway - welcome. I hope you find the articles on this blog interesting and helpful.
Subscribe to:
Posts (Atom)