Welcome

Extending XDoclet Spring Module

XDoclet is a wonderful tool, and we extensively make use of it in our current project to generate Hibernate and Spring configuration files. Our aim is to maintain no configuration file apart from our source code. XDoclet’s help is great in achieving this, but sometimes it requires modifications to keep up with that mission.

We made several modifications to XDoclet Spring Module, and I want to explain those modifications to you briefly.

One modification we made is to generate property element which has value sub-element. It has already been supported by current module, but if we wanted to generate one that provides values to be processed by a Spring Property Editor, each value in a separate line, like below;

<property name="objectDefinitionSource">
            <value>
                         \A/login.jsp\Z=ROLE_ANONYMOUS
                         \A/logout.jsp\Z=ROLE_ANONYMOUS,ROLE_USER
                         \A.*index.jsp\Z=ROLE_USER
            </value>
</property>

then we have to modify spring_xml.xdt file and add following;

<XDtClass:ifHasClassTag tagName="spring.property" paramName="value.list">
    <value>
        <XDtClass:forAllClassTagTokens tagName="spring.property" paramName="value.list" delimiter="|">
            <XDtClass:currentToken/>
        </XDtClass:forAllClassTagTokens>
    </value>
</XDtClass:ifHasClassTag>

<XDtMethod:ifHasMethodTag tagName="spring.property" paramName="value.list">
    <value>
        <XDtMethod:forAllMethodTagTokens tagName="spring.property" paramName="value.list" delimiter="|">
        <XDtMethod:currentToken/>
        </XDtMethod:forAllMethodTagTokens>
    </value>
</XDtMethod:ifHasMethodTag>

Here comes its usage in our source code. Please be aware of the use of  | (pipe) symbol, as it is used as the delimiter between elements of list;

/**
 * @spring.bean id = "filterSecurityInterceptor"
 * @spring.property name = "objectDefinitionSource" value.list ="
 *                      \A/login.jsp\Z=ROLE_ ANONYMOUS |
 *                      \A/logout.jsp\Z=ROLE_ ANONYMOUS,ROLE_USER |
 *                      \A.*index.jsp\Z=ROLE_USER |
 *                    
 */
public class FilterSecurityInterceptor extends                       net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor {
}

Another extension is to generate a property element with list sub-element. This list sub-element’s each child element is a ref sub-element again.

<property name="providers">
<list>
<ref bean="passwordDaoAuthenticationProvider"/>
<ref bean="testingAuthenticationProvider"/>
<ref bean="anonymousAuthenticationProvider"/>
</list>
</property>

We need to add following lines to be able to achieve this;

<XDtClass:ifHasClassTag tagName="spring.property" paramName="list.ref">
    <list>
        <XDtClass:forAllClassTagTokens tagName="spring.property" paramName="list.ref">
            <ref bean="<XDtClass:currentToken/>"/>
        </XDtClass:forAllClassTagTokens>
    </list>
</XDtClass:ifHasClassTag>

<XDtMethod:ifHasMethodTag tagName="spring.property" paramName="list.ref">
    <list>
        <XDtMethod:forAllMethodTagTokens tagName="spring.property" paramName="list.ref">
            <ref bean="<XDtMethod:currentToken/>"/>
        </XDtMethod:forAllMethodTagTokens>
    </list>
</XDtMethod:ifHasMethodTag>

it’s usage in our source code;

/**
 * @spring.bean id = "authenticationManager"
 * @spring.property name = "providers" list.ref = "passwordDaoAuthenticationProvider,testingAuthenticationProvider,anonymousAuthenticationProvider"
 *
 */
public class ProviderManager extends net.sf.acegisecurity.providers.ProviderManager {
}

Our final modification is again for property element. This time, it consists of props sub-element. Props element in turn consists of one or more prop child element, each having key attribute and text value. For example;

<property name="hibernateProperties">
    <props>
        <prop key="hibernate.dialect">
            net.sf.hibernate.dialect.Oracle9Dialect
        </prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.show_sql">true</prop>
    </props>
</property>

<XDtClass:ifHasClassTag tagName="spring.property.props">
<property name="<XDtClass:classTagValue tagName="spring.property.props" paramName="name"/>">
    <props>
        <XDtClass:forAllClassTags tagName="spring.property.prop">
        <prop key="<XDtClass:classTagValue tagName="spring.property.prop" paramName="key"/>">                                                               
            <XDtClass:classTagValue tagName="spring.property.prop" paramName="value"/>
        </prop>
        </XDtClass:forAllClassTags>
    </props>
</property>
</XDtClass:ifHasClassTag>

<XDtMethod:ifHasMethodTag tagName="spring.property.props">
<property name="<XDtMethod:methodTagValue tagName="spring.property.props" paramName="name"/>">
 <props>
     <XDtMethod:forAllMethodTags tagName="spring.property.prop">
        <prop key="<XDtMethod:methodTagValue tagName="spring.property.prop" paramName="key"/>">                                                                   
             <XDtMethod:methodTagValue tagName="spring.property.prop" paramName="value"/>
        </prop>
     </XDtMethod:forAllMethodTags>
 </props>
</property>
</XDtMethod:ifHasMethodTag>

And its usage in our source code;

/**
 * @spring.bean id = "sessionFactory"
 * @spring.property.props name = "hibernateProperties"
 * @spring.property.prop key = "hibernate.dialect" value = "net.sf.hibernate.dialect.Oracle9Dialect"
 * @spring.property.prop key = "hibernate.hbm2ddl.auto" value = "update"
 * @spring.property.prop key = "hibernate.show_sql" value = "true"
 */
public class LocalSessionFactoryBean extends                    org.springframework.orm.hibernate.LocalSessionFactoryBean {
}

All of our extensions are both in class level and method level. In addition to those additions, we also modified xtags.xml file. This file is neccessary for code assist tools, in order to provide suggestions inside code editors.

Below two go in property tag;

<parameter type="text">
    <name>list.ref</name>
    <usage-description>Comma-separated list of bean names</usage-description>
    <mandatory>false</mandatory>
</parameter>

<parameter type="text">
    <name>value.list</name>
    <usage-description>Pipe separated values to provide with property editor.</usage-description>
    <mandatory>false</mandatory>
</parameter>

<tag>
    <level>class</level>
    <name>spring.property.props</name>
    <usage-description></usage-description>
    <unique>true</unique>

    <parameter type="text">
        <name>name</name>
        <usage-description></usage-description>
        <mandatory>true</mandatory>
        </parameter>
</tag>
<tag>
    <level>class</level>
    <name>spring.property.prop</name>
    <usage-description></usage-description>
    <unique>false</unique>
    <parameter type="text">
        <name>key</name>
        <usage-description></usage-description>
        <mandatory>true</mandatory>
    </parameter>

    <parameter type="text">
        <name>value</name>
        <usage-description></usage-description>
        <mandatory>true</mandatory>
    </parameter>
</tag>