March 26, 2005

XDoclet Hibernate "joined-subclass" tags don't work.

(A quick apology for any readers who have no idea what this posting is about. In my work I've come across a really annoying bug in some technology, and my "Googling" research didn't come up with any good answers. It has taken me a few days to really get all of this right, so I'm hoping if some poor sod has the same problem, he or she will come across this blog posting in order to save a massive amount of time.)

I am working on an enterprise application using J2EE (JBoss) with Hibernate as the substitute for the brain-dead CMP 2.0 Entity Beans. Our development environment is Eclipse with XDoclet.

I was attempting to create an implementation of "Joined Subclasses" via the @hibernate.joined-subclass command. Here's the really brain-dead thing: from what I can tell, this XDoclet class tag simply does not work, and I'm not sure it ever did! In my XDoclet book (and the Javadoc api page) there's a @hibernate.joined-subclass-key which would be necessary to fully-define a joined subclass, but in the xdoclet module this tag doesn't appear to exist. I'd found a web forum entry where someone claimed Eclipse's autocompletion didn't recognize it, but that you could manually type it in, but I wasn't able to get it to work!

Essentially, it appears someone defined this in the API (because, Hell, it is really important to have to have a 'complete' XDoclet implementation) but I honestly see no indication that it ever worked.

Now I had to figure out how to minimize the degree by which I was screwed. The obvious solution would be to hand-craft the hibernate xml descriptors for my subclasses and manually copy them into the superclass descriptor. This would suck because then I couldn't auto-generate the superclass descriptor without overwriting my manual entries.

But wait! If you look at the XDoclet autogenerated XML there's a comment telling you a specific filename you could create and place in your merge directory in order to merge non-xdoclet descriptors into the superclass descriptor. To make a long story short: it didn't seem to work. I've done mergepoint work before in XDoclet, but the hand-crafted definitions for the subclasses wasn't getting inserted. There's a chance I was doing something bone-headed, but I didn't have time to keep hammering at that solution.

Then I looked at the Hibernate2 DTD and came to a realization: you don't have to insert joined-subclass elements inside the superclass's element: you can have them standalone as long as you fill in the extends="superclass" attribute in the tag.

So here's what I did:

1. Create the subclass, but define it as a regular @hibernate.class so that a descriptor file gets generated. (Then remove the @hibernate.class tag so XDoclet never tries to recreate a descriptor.)

2. Move the foo.hbm.xml file to a safer directory where it won't get overwritten or erased by the build system. Hand-edit the file by removing any element that belong to the superclass, especially the id.

3. Change the tag to and inside the make sure you define a element.

Modify your packing system so these static files get included in the HAR archive or wherever you have the rest of the *.hbm.xml files. Remember, although XDoclet creates a mirror package-name directory structure for its hbm.xml files, Hibernate itself doesn't care... it just searches for and reads every file it can find in the archive, so don't waste time trying to get your custom hbm.xml files into the appropriate directory.

That's it. That's everything I know. I hope someone reads this and is saved days of fussing and can get back to productive work!

Posted by Murray Todd Williams at March 26, 2005 10:51 AM
Comments

Manual entry works with XDoclet 1.2.2.
Autocomplete can be achieved by declaring a xdoclet template in JBoss IDE.

Posted by: Ashish at March 30, 2005 04:34 PM

Thanks a lot for this article...
This has been a really frustrating issue.
I have spent the last day trying everything!
Tried xdoclet 1.3 (CVS) that didn't work...
Tried xdoclet2 - that sux big time... it is no where in the vicinity of bieng considered as usable s/w.

Posted by: Nikhil Gupte at April 6, 2005 09:59 PM

I guess it must be implemented since it works for me...

Below is an example.

The parent class:

----------------------------------
import java.io.Serializable;
import java.math.BigDecimal;

/**
* @hibernate.class
* table="ANIMAL"
*/
public class Animal implements Serializable {
private BigDecimal myId;
private String myAge;

public Animal() {
}

/**
* @hibernate.id
* generator-class="assigned"
* type="java.math.BigDecimal"
* column="ID"
*/
public BigDecimal getId() {
return myId;
}

public void setId(BigDecimal theId) {
myId = theId;
}

/**
* @hibernate.property
* column="AGE"
*/
public String getAge() {
return myAge;
}

public void setAge(String theAge) {
myAge = theAge;
}
}
----------------------------------

The child class:

----------------------------------
import java.io.Serializable;

/**
* @hibernate.joined-subclass
* table="CAT"
*
* @hibernate.joined-subclass-key
* column="ID"
*/
public class Cat extends Animal implements Serializable {

/** identifier field */
private String myName;

/** default constructor */
public Cat() {
super();
}

/**
* @hibernate.property
* column="NAME"
*/
public String getName() {
return myName;
}

public void setName(String theName) {
myName = theName;
}
}
----------------------------------

... this is generated when running XDoclet:

----------------------------------
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping
>
<class
name="Animal"
table="ANIMAL"
dynamic-update="false"
dynamic-insert="false"
select-before-update="false"
optimistic-lock="version"
>

<id
name="id"
column="ID"
type="java.math.BigDecimal"
>
<generator class="assigned">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Animal.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>

<property
name="age"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="AGE"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Animal.xml
containing the additional properties and place it in your merge dir.
-->

<joined-subclass
name="com.ipx.hibernate.Cat"
table="CAT"
dynamic-update="false"
dynamic-insert="false"
>
<key
column="ID"
/>
<property
name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="NAME"
/>

</joined-subclass>

</class>

</hibernate-mapping>

Posted by: Osten at May 4, 2005 01:38 AM

XDoclet 1.2.3 works for me as well, as per Osten's example. I spent ages trying to figure out why XDoclet wasn't generating the joined-subclass' mapping document, when I realised it had generated the joined-subclass mapping _inside_ the superclass.

Very annoying as there appears to be no way to override it, but given the fact that all my Hibernate mappings are generated, I'm not too worried about overly complex metadata.

Posted by: Marvin at May 4, 2005 11:05 PM

It doesn't work where there are more than 2 classes in the heirarchy...

Also, if there are say 3 classes, and the middle class doesn't need to be persisted, xdoclet cannot proceed to the very last child unless the middle class too is given un-necessary hibernate tags.

Posted by: nikhil gupte at July 6, 2005 08:21 AM

I just noticed all this discussion. As it turns out, the problem had been mine. I think it was that I had forgotten to explicitly write what the parent class was inside the subclass. I'd assumed that XDoclet would have parsed that and looked things up.

It did throw me later that the generated code was inside the parent class's mapping file. Generally I'm getting more frustrated with XDoclet and I'm ready to get us away from that tool altogether. Most agonizing is the fact that XDoclet breaks if you use ANY of the Java 1.5 language features. I've seen indication somewhere that this is fixed as of XDoclet 1.5, but I can't find a 1.5 anywhere, and it certainly won't be compatible with JBoss-IDE in Eclipse.

I'm just anxious to move to Hibernate 3 Annotations as quickly as humanly possible!

Posted by: Murray Todd Williams at August 21, 2005 05:15 PM
Post a comment












Remember personal info?