I've been trying to update the Hibernate module to support mapping a
top level interface as the <class> with concrete subclasses as
<subclass> elements.  The change was actually very easy, with a minor
update to the HibernateTagsHandler class.

However, the mapping file is generated incorrectly.  In the example
below, I have an interface named Address with an implementing class
called AddressImpl (If you don't want to read the mapping file, I
summarize the problem below):

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

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

<hibernate-mapping
>
    <class
        name="example.Address"
        table="address"
        lazy="true"
        discriminator-value="interface"
    >

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

        <discriminator
            column="c"
            type="string"
            length="10"
        />

        <property
            name="line1"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line1"
            length="60"
            not-null="true"
        />

        <property
            name="line2"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line2"
            length="60"
        />

        <property
            name="line3"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line3"
            length="60"
        />

        <property
            name="city"
            type="java.lang.String"
            update="true"
            insert="true"
            column="city"
            length="20"
            not-null="true"
        />

        <property
            name="state"
            type="java.lang.String"
            update="true"
            insert="true"
            column="state"
            length="2"
        />

        <property
            name="zipCode"
            type="java.lang.String"
            update="true"
            insert="true"
            column="zipCode"
            length="10"
            not-null="true"
        />

        <property
            name="primaryAddress"
            type="java.lang.Boolean"
            update="true"
            insert="true"
            column="primaryAddress"
        />

        <property
            name="name"
            type="java.lang.String"
            update="true"
            insert="true"
            column="name"
            length="250"
        />

        <property
            name="created"
            type="timestamp"
            update="false"
            insert="true"
            column="created"
        />

        <many-to-one
            name="creatingUser"
            class="example.User"
            cascade="none"
            outer-join="auto"
            update="false"
            insert="true"
            column="creatingUser"
        />

        <property
            name="updated"
            type="timestamp"
            update="true"
            insert="false"
            column="updated"
        />

        <many-to-one
            name="updatingUser"
            class="example.User"
            cascade="none"
            outer-join="auto"
            update="true"
            insert="false"
            column="updatingUser"
        />

        <!--
            To add non XDoclet property mappings, create a file named
                hibernate-properties-Address.xml
            containing the additional properties and place it in your merge dir.
        -->
        <subclass
            name="example.AddressImpl"
            discriminator-value="address"
        >
        <property
            name="line1"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line1"
            length="60"
            not-null="true"
        />

        <property
            name="line2"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line2"
            length="60"
        />

        <property
            name="line3"
            type="java.lang.String"
            update="true"
            insert="true"
            column="line3"
            length="60"
        />

        <property
            name="city"
            type="java.lang.String"
            update="true"
            insert="true"
            column="city"
            length="20"
            not-null="true"
        />

        <property
            name="state"
            type="java.lang.String"
            update="true"
            insert="true"
            column="state"
            length="2"
        />

        <property
            name="zipCode"
            type="java.lang.String"
            update="true"
            insert="true"
            column="zipCode"
            length="10"
            not-null="true"
        />

        <property
            name="primaryAddress"
            type="java.lang.Boolean"
            update="true"
            insert="true"
            column="zipCode"
            length="10"
            not-null="true"
        />

        <property
            name="primaryAddress"
            type="java.lang.Boolean"
            update="true"
            insert="true"
            column="primaryAddress"
        />

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

        </subclass>

    </class>

</hibernate-mapping>

As you can see (or not see if you skipped it), XDoclet generates the
properties for the interface, which is correct, as well as for the
subclass, which is incorrect.  The Hibernate templates explicitly
state that superclasses shouldn't be checked, which also implies that
implemented interfaces shouldn't be checked for @hibernate tags. 
However, that's clearly not happening.  Here's a snippet from the
hibernate-subclass.xdt template:

            <XDtMethod:forAllMethods superclasses="false" sort="true">
                <XDtMerge:merge
file="xdoclet/modules/hibernate/resources/hibernate-properties.xdt">
                </XDtMerge:merge>
            </XDtMethod:forAllMethods>

Does anyone have suggestions on a resolution or a workaround? 
Supporting interfaces would be a nice addition to this module.  My
updated HibernateTagsHandler#forAllSubclasses method is below:

    public void forAllSubclasses(String template, Properties
attributes) throws XDocletException
    {

        Log log = LogUtil.getLog(HibernateTagsHandler.class,
"forAllSubclasses");

        try {

            String typeName = getCurrentClass().getQualifiedName();

            if (log.isDebugEnabled())
                log.debug("typeName=" + typeName);

            Collection classes = getXJavaDoc().getSourceClasses();
            XClass clazz;

            for (Iterator i = classes.iterator(); i.hasNext(); ) {
                clazz = (XClass) i.next();

                log.debug("clazz=" + clazz);

                if (DocletSupport.isDocletGenerated(clazz)) {
                    log.debug("isDocletGenerated");
                }
                else {
                    if (clazz.getSuperclass() != null &&
clazz.getSuperclass().getQualifiedName().equals(typeName)) {
                        log.debug("is a subclass");

                        XClass current = getCurrentClass();

                        pushCurrentClass(clazz);
                        generate(template);
                        popCurrentClass();

                        if (getCurrentClass() != current)
                            setCurrentClass(current);
                    }

                    Collection interfacesCollection = clazz.getInterfaces();

                    if (interfacesCollection != null) {
                        for (Iterator interfaces =
interfacesCollection.iterator(); interfaces.hasNext(); ) {
                            XClass iface = (XClass) interfaces.next();

                            if (iface.getQualifiedName().equals(typeName)) {
                                XClass current = getCurrentClass();

                                pushCurrentClass(clazz);
                                generate(template);
                                popCurrentClass();
                                if (getCurrentClass() != current)
                                    setCurrentClass(current);
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e) {
            log.error("exception occurred", e);
        }
    }

I think it's unlikely that the problem is in
xjavadoc.AbstractClass#getMembers(boolean, boolean), but that's where
this trail has led me.  However, I'm hesitant to change that class for
obvious reasons.


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id396&op=click
_______________________________________________
xdoclet-devel mailing list
xdoclet-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/xdoclet-devel

Reply via email to