Hi all, my first post on these forums.
One month ago, if you'd asked what I knew about Hibernate, I'd have gone off about something animals do in the winter, but today, after a rather intense first two weeks, and some interesting discoveries, I now have a system in place, that goes:
DTD -> (XSL) -> "pure XML" -> XSD -> Hibernate -> MS-SQL
and do the complete reverse to the original format.
I do agree, that the whoel getter/setter issue is a problem with JAXB and Hibernate. Not only that, but our dear users (don't we all love them?) decided that they would send in their DTD fields in any order. This meant that I had to create 1-1-M bridging objects (tables) to allow for me to use the <xsd:all> tags.
The problem with the creation of the getter/setter for the parent objects - for the hibernate mapping properties, was solved by a colleague, who apparently loves do machine code. He solved this problem by modifying the ant-build build.xml like this:
-------------------------------------------------------------------------------------
<target name="codegen" description="Generate JAXB classes" >
<!-- generate the Java content classes from the schema -->
<echo message="Compiling the schema..."/>
<property name="build.src" value="." />
<xjc schema="input.xsd" target="${build.src}" package="my.package"/>
<replace dir="${build.src}" token="protected java.util.List"
value="protected java.util.List" />
<replaceregexp match="java\.util\.List get(.+)\(\);"
replace="java.util.List /\*NOP\*/ get\1\(\);
void set\1\(java.util.List _\1\);" byline="true" >
<fileset dir="${build.src}" />
</replaceregexp>
<replaceregexp match="new java\.util\.List()"
replace="new java\.util\.ArrayList" byline="true" >
<fileset dir="${build.src}" />
</replaceregexp>
<replaceregexp match="public java.util.List get(.+)\(\).*\{"
replace="public void set\1\(java.util.List _\1\) \{
this._\1 =new com.sun.xml.bind.util.ListImpl( _\1);
\}
public java.util.List /\*NOP\*/get\1\(\) \{" byline="true" >
<fileset dir="${build.src}" />
</replaceregexp>
<!-- generate the javadocs from the content classes -->
<mkdir dir="docs/api"/>
<javadoc packagenames="my.package"
sourcepath="."
destdir="docs/api"
windowtitle="Generated Interfaces for input.xsd">
<classpath refid="classpath" />
</javadoc>
</target>
------------------------------------------------------------------------------------
If you can read that, basically, he tells it to traverse the package looking for anywhere that the JAXB generates a java.util.List GET (1-to-Many) and replaces that with with both a GET and SET...that's if I understand it correctly. :)
To aid in my JAXB to Hibernate, I create a 0-1 element in each child Complex-Type...like this:
------------------------------------------------------------------------------------
<xsd:complexType name="Grandparent">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="1">
<xsd:element name="Parent" type="Parent" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="HumanID" type="xsd:long"/>
</xsd:complexType>
<xsd:complexType name="Parent">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="1">
<xsd:element name="Grandparent" type="Grandparent" minOccurs="0"/>
<xsd:element name="Children" type="Children" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="HumanID" type="xsd:long"/>
</xsd:complexType>
------------------------------------------------------------------------------------
If I recall properly, JAXB will create a getter for the Grandparent in Parent, and that little build.xml change will create a setter for it.
The reason I do this, is because Java works in a "Parent-has-children" way, while relational databases work in a "child-has-Parent" way...exactly inverse. By creating the link to the Grandparent element in my XSD, I create what I think as a trully neutral object design. From there you can map to XML or to databases. Of course, there is one caveat with this, and PLEASE don't forget this. When you marshall your code against this type of XSD, PLEASE PLEASE PLEASE PLEASE PLEASE, go through your tree and set the "Grandparent" type elements to null, otherwise you will get an infinite loop...
I hope this provides a little assistance. I'll start checking the forums more now that I've got my system running very smoothly (with great effort and great thanks to Hibernate). And I'd also love to hear if someone found another way to do it.
-G
PS. My thanks Mikey N. for his "hack".
|