Tuesday, October 17, 2006

JAXB, JIBX and Reverse Engineering XSD from my Java Object Model

I've got the requirement to output the contents of my object model in a readable fashion. What could be more readable than XML which led me to JAXB. The onyl problem is, with JAXB you start with the schema and go in the other direction. Step up to the mark JiXB. This allows you to go the other way and was very simple to get up and running.
  1. First step was download the bits and "install" (i.e. unzip) them (the "bits" I used were the core libs plus the utils. In my case "jibx_1_1.zip" and "jibxtools-beta2.zip"
  2. Copy the jibx-genbinding.jar and jibx-genschema.jar files from the tools zip file to the ./lib directory of your main JiBX "install"
  3. Open a command line and change directory to where your compiled classes are (NOTE: not the java source files as jibx uses introspection with the class files to do it's work. If they are in a package structure, make sure you are at the root of the package structure so that the cp declaration in the following command works. Otherwise you'll get a JiBXException about classes not being found)
  4. Auto-generate the binding file ("binding.xml") for your classes by running the following command:
    • java -cp . -jar /home/myexampleuser/jibx/lib/jibx-genbinding.jar com.myexample.ClassA com.myexample.ClassB
  5. I had warnings at this stage about references to interfaces or abstract classes:
    • Warning: reference to interface or abstract class java.util.Set requires mapped implementation
  6. I'd gone outwith the standard example on the website. Time to hit google... It turns out that out-of-the-box JiBX can handle some java.util.Collections fine like ArrayLists which my model also used but java.util.Sets (I'd used HashSet) were a little more troublesome. I needed to edit the newly created binding.xml file each time a Set-based relationship was found as follows:
    • Original: <structure field="mySetOfAObjects" usage="optional">
      </structure>
    • Updated: <collection field="mySetOfAObjects" factory="com.myexample.ObjectB.hashSetFactory">
      <structure type="com.myexample.ObjectB" usage="optional"/>
      </collection>
  7. You'll have noticed that I seem to be calling a method "hashSetFactory()" on ClassB. This is the case, and it won't be there already. You need to add a static method to this class as follows:
    • private static Set hashSetFactory() { return new HashSet();}
  8. You'll now be able to run the second command which will generate your xsd schema for you based on your new mapping binding.xml file:
    • java -cp . -jar /home/myexampleuser/jibx/lib/jibx-genschema.jar binding.xml
  9. This will then generate you the xsd schema file you have been looking for all along.