Ryan's Blog
The JiBX Conundrum
Overview
JiBX is a binding framework from XML to Java Objects and back. JiBX could be used in place of frameworks like XMLBeans, Castor or just plain JDOM parsing. JiBX works through a JiBX binding file. It essentially connects a particular tag value or attribute value to a field in a Java class. This XML mapping file is read into the JiBX compiler and then the Java classes that the XML is bound to, are instrumented to handle the XML. Basically this boils down to many methods being created on the Java class that when passed a Marshalling or Unmarshalling context will set the appropriate variables with the correct value. I'm still not convinced that JiBX has saved me time, or whether it will be
better in the long run over manual DOM style XML parsing.
Setting the Stage
The end result of this XML parsing is going to be web services. Both requesting information from web services developed by vendors and providing web services to those vendor systems. To facilitate this, the Acord XML format was chosen. To those not familiar with Acord, it is a large insurance XML specification (by large, if I remember correctly, the schemas for this spec was about 800 KB total). The specification is so large because it would theoretically handle all of the insurance related transactions and messages that any organization would need. Putting this requirement in a technical context, this throws out frameworks like XMLBeans. Generating code for all of these tags and the awkward Acord structure is not an option. Next is that this must work on JDK 1.4, with Websphere. It must be JDK 1.4 because these need for this code to be ran from IBM portlets and the current IBM portlet engine only runs on JDK 1.4. Websphere also presents some concerns because XML parsing using the frameworks not already included in Websphere has always gone bad for me. The final requirement is that it must have Spring-WS support. Spring-WS works well in a 1.4 environment and we were planning on using that for the web service framework.
JiBX is the Solution?
With the requirements above, the solution came down to Castor or JiBX. Both looked like they did what we needed to do, however we had quite a few problems getting Castor, Spring-WS and Websphere along with the old version of the JDK. Oddly enough the fix for our problems was switching to 1.5 (not an option). So we were left with JiBX or parsing the XML by hand using DOM or something similar. Obviously not wanting to go back to the bad old days of hand parsing we went with JiBX. It supports mapping to/from an XML and Object model. There's no code generation based on schema and it works well in 1.4. Before going into some of the problems I had with JiBX, I'll start by covering what JiBX does well. The benefits of JiBX over XMLBeans for me is that most of the Acord schema, I don't care about. Most of the tags I won't use and even for a particular Acord transaction, I don't care about many of the tags. By "don't care" I mean that either my system can't supply that value, or if that value is supplied, I can't do anything with it, so it might as well not even be there from my perspective. Another key point of JiBX is that I can keep my object model how I would like it. JiBX maps an XML to my object model. So in the case of Acord, the XML structure is pretty obscure and difficult to mimic as an object model. Mapping the awkward Acord structure to something that makes more sense from my application's perspective is a great feature. Another benefit of JiBX is that it performed pretty well with the XMLs that I have sent it. I don't have any benchmarks, but I also haven't had any complaints about speed.
Initial JiBX Pains
So part of the initial pain of JiBX is how to instrument the bytecode. Since the JiBX compiler needs to read in the XML mapping file and modify the Java bytecode, this needs to happen as part of the build process. This isn't a big deal for Ant because JiBX has a nice set of Ant targets for it. Where this becomes a problem is in the day to day development in the IDE. I was developing a web service which, for local development at least I was deploying to Tomcat. Instrumenting the bytecode before it was deployed in Tomcat ended up being quite a task. I was using Rational Application Developer (which might have played a role in the problem) and had a difficult time with the solutions listed on the JiBX site. They recommend creating a custom Builder in Eclipse or using a plugin that they wrote that is still in the early stages. I tried both of these and didn't have any luck. Even when the compiling worked, it would always try to autodeploy before the bytecode manipulation was done. So I ended up manually running the Ant target that did the instrumenting and then either deploying via an Ant target or manually publishing to Tomcat through the Eclipse WTP Server plugin.
Reusability Problems
Probably my biggest complaint about JiBX is around the reusability of JiBX code. I was developing many web services and clients for the vendor web services. Since these messages were Acord based, there were many common things. For example, there are Acord code values all over the message. These Acord codes have two parts, one is the numeric value for the code and then the text value for the code. My first reaction was to create a shared JAR file with all of these common things in it. So it would have base classes that had common header pieces, and these Acord Codes and more. The problem is, JiBX cannot bind into Java classes that are in a JAR. So for example, I created the AcordCode classes and put it into a JAR, JiBX would not bind it even if it was in the classpath. The answer to this is to create a "do nothing" subclass of AcordCode. It defines no methods, no variables etc, just extends it. The reason this worked is that JiBX would manipulate the subclass and trap calls to the superclasses variables. Another gotcha here was that for this to work AcordCode needed to have it's variables set to protected or public. Since JiBX by default goes after the variables directly, if it's marked as private, it can't get to it through the subclass. It's important here to note that JiBX does support using getters and setters vs. using the variables directly. This however makes the XML binding file much more verbose. When used with a field like the Acord code fields, it can become very cumbersome.
Another point of non-resuability is around the binding files themselves. When you are working with JiBX, especially with a big spec like Acord, you find yourself spending a lot of time on the bindings. There's a lot of time and a lot of code that goes into these binding files. The problem is there is very limited reuse on these binding files. The binding files can be reused inside the same project, but they cannot be reused inside of other projects. For example, there are several "header" type of fields in an Acord message. Fields like a GUID for the transaction, an indication of which transaction is being used etc. I put these fields in a base Acord message (marking them as protected). This worked out fine because it made sense to subclass them anyway. The problem here is that the binding to those tags has to be repeated on each project. So each project needs to define that the GUID needs to map to the GUID field on that base class. JiBX does not allow reading in these binding files from a JAR. In my opinion, this is a big deal. Now I am forced to either copy and paste the bindings or reinvent the wheel each time.
One more problem I had was on the reusability of the binding files within a project. Knowing that it was difficult to share common classes across projects, I combined a couple of clients that used a similar Acord message into one client jar. Often with web services you want to wrap the message in a tag that maps to the operation. So for this, I ended up having three messages that were basically the same, except the tag that wraps it was different. This is actually quite hard in JiBX. What I wanted was to define a mapping, of a bunch of fields and tags that didn't map directly to a particular class. Then I wanted to include that in a mapping to a class. This isn't possible in JiBX, so I ended up moving as much of it as I could to their own mappings. In the end, I was able to cut down on some of the duplication, but I sill needed to duplicate about 20-30 lines of the binding file to each of the three messages.
Quirks
I also ran into quite a few quirks of JiBX. Basically these quirks came down to the creators of JiBX made design decisions that were different from what I needed using Acord. One example of this is using a non-wrapped repeating tag with flexible elements. JiBX has a setting called "flexible" that basically tells JiBX that if there is a tag there that is not in the binding file, to ignore it. This is definitely necessary when working with Acord because we can't handle all possible tags and there are many tags that can be added and still validate against the schema. The problem occurs when there is a repeating tag, that has a flexible parent tag. As an example:
<tag>
<tagA/>
<tagB/>
</tag>
<tag>
<tagA/>
<tagB/>
</tag>
Attempting to bind to this in JiBX will cause an error. The easy way to fix this (from the JiBX developers) is to create a wrapping tag like below:
<wrappingtag>
<tag>
<tagA/>
<tagB/>
</tag>
<tag>
<tagA/>
<tagB/>
</tag>
</wrappingtag>
Since it's not an option to change the Acord specification, I had to find a workaround here. Basically I needed to write a custom marshaller and unmarshaller for these tags. I'll post my solution in a follow up blog entry. I also ran into a known bug with JiBX around optionally populated structure elements. So in JiBX a structure is just a grouping of tags, or an aggregate. So in the above example, <tag/> could be a structure or <wrappingtag/>. JiBX has logic built in that will not populate a tag if there is no value for the field associated with that tag. So in the above example, if the Java variable associated with tagA was null, tagA would not appear in the output XML. This does not work properly with structure attributes. Where this caused me problems is with the Acord codes. So above I stated that Acord codes correspond to an attribute and a tag value. This requires a structure in JiBX. So in the event that there isn't a value for that Acord code, it would still output an empty tag for that Acord code. To get around this, I had to create what JiBX calls a "test-method" that returns true or false as to whether or not it should output that tag. This wasn't a huge deal, but it was quite a bit of extra work when there is ten fields that require it.
Conclusion
I ended up continuing to use JiBX despite the pains of using it. The marks against it weren't compelling enough for me to rework what I had already done in JiBX. I think that once we are able to move to JDK 1.5, perhaps the XML parsing options should be resurveyed. I will however definitely give quite a bit of thought to whether or not to use JiBX the next time around.
Posted at 09:58AM Feb 18, 2008 by Ryan Senior in Programming | Comments[0]