XDoclet is an open-source project hosted at http://xdoclet.sourceforge.net. It is an extension of Sun's javadoc tool that allows you to embed well-formed tags in java source code and output metadata of a particular type. In the case of the JDODoclet, you can generate a filename.jdo file based on various tags starting with @jdo:. Any class that has the @jdo:persist class-level tag will be processed. This allows for all refactoring to be done in just one place (the java source code file), without the developer needing to manually ensure that the .jdo metadata file is always synchronized with the state of the java source code.
In order to utilize the XDoclet task, you will need to download the XDoclet libraries separately from http://xdoclet.sourceforge.net and add them to your CLASSPATH. The JDODoc task can then be executed from the build.xml as follows:
Example 9.6. Invoking the JDO Metadata generator from an Ant build.xml file
<target name="generateJdoMetadata"> <taskdef name="jdodoclet" classname="com.solarmetric.modules.integration.ant.KodoDocletTask"/> <jdodoclet sourcepath="${basedir}" destdir="${classes}"> <fileset dir="${basedir}"> <include name="**/*.java"/> </fileset> <!-- perform the actual transformation here --> <jdotags/> </jdodoclet> </target>
An example of a commented file is as follows:
Example 9.7. Source code comments for automatic JDO Metadata generation
package samples.xdoclet; import java.util.*; /** * This is the TestDoclet example class. It is used to * demonstrate automatic generation of the * TestDoclet.jdo file based on the jdo: tags * in the source code. * * Note that the double-$ for inner class names is required * in order to escape ant variable handling. * * The jdo:persist tag is required for the XDoclet to know that we * should generate persistence information for this class. * * @jdo:persist * @jdo:identity-type application * @jdo:objectid-class TestDoclet$$Id * @jdo:requires-extent false * @jdo:extension vendor-name="kodo" key="table" * value="DOCLET_TEST_TABLE" * @jdo:extension vendor-name="kodo" key="pk-column" * value="TEST_PK_COLUMN" * @jdo:extension vendor-name="kodo" key="lock-column" * value="TEST_LOCK_COLUMN" * @jdo:extension vendor-name="kodo" key="class-column" * value="TEST_CLASS_COLUMN" * * @author Marc Prud'hommeaux */ public class TestDoclet { /** * @jdo:primary-key true * @jdo:extension vendor-name="kodo" key="column-length" * value="10" */ private String pk1; /** * @jdo:primary-key true * @jdo:extension vendor-name="kodo" key="column-length" * value="20" */ private String pk2; /** * @jdo:persistence-modifier transactional * @jdo:null-value exception * @jdo:default-fetch-group true * @jdo:embedded true * @jdo:extension vendor-name="kodo" key="data-column" * value="NAME_DATA" */ private String name; /** * @jdo:extension vendor-name="kodo" key="data-column" * value="MEMO_COLUMN" * @jdo:extension vendor-name="kodo" key="column-length" * value="-1" */ private String memo; /** * @jdo:extension vendor-name="kodo" key="data-column" * value="AGE_DATA" */ private int age; /** * @jdo:collection element-type="TestDocletChild" * embedded-element="false" * @jdo:extension vendor-name="kodo" key="table" * value="TEST_XREF_DOCLET_TABLE" * @jdo:extension vendor-name="kodo" key="ref-column" * value="TEST_CHILDREN_REF_COLUMN" * @jdo:extension vendor-name="kodo" key="order-column" * value="TEST_CHILDREN_ORDER_COLUMN" * @jdo:extension vendor-name="kodo" key="inverse" * value="childInverse" */ private Collection children = new ArrayList (); /** * @jdo:map key-type="String" embedded-key="false" * value-type="Integer" embedded-key="false" * @jdo:extension vendor-name="kodo" key="key-column" * value="TEST_MAP_KEY" */ private Map testMap = new HashMap (); /** * Application identity class. */ public static class Id { public String pk1; public String pk2; public boolean equals (Object other) { return other.getClass () == this.getClass () && ((Id)other).pk1.equals (pk1) && ((Id)other).pk2.equals (pk2); } public int hashCode () { return pk1.hashCode () + pk2.hashCode (); } } }
<?xml version="1.0" encoding="UTF-8"?> <!-- This file is auto-generated by the com.solarmetric.modules.integration.ant.JDODoclet ant task. Bear in mind that any changes to this file will be overwritten if the task is re-run. --> <jdo> <package name="samples.xdoclet"> <class name="TestDoclet" identity-type="application" objectid-class="TestDoclet$Id" requires-extent="false" > <extension vendor-name="kodo" key="table" value="DOCLET_TEST_TABLE" /> <extension vendor-name="kodo" key="pk-column" value="TEST_PK_COLUMN" /> <extension vendor-name="kodo" key="lock-column" value="TEST_LOCK_COLUMN" /> <extension vendor-name="kodo" key="class-column" value="TEST_CLASS_COLUMN" /> <field name="age"> <extension vendor-name="kodo" key="data-column" value="AGE_DATA" /> </field> <field name="children"> <collection element-type="TestDocletChild" embedded-element="false" /> <extension vendor-name="kodo" key="table" value="TEST_XREF_DOCLET_TABLE" /> <extension vendor-name="kodo" key="ref-column" value="TEST_CHILDREN_REF_COLUMN" /> <extension vendor-name="kodo" key="order-column" value="TEST_CHILDREN_ORDER_COLUMN" /> <extension vendor-name="kodo" key="inverse" value="childInverse" /> </field> <field name="memo"> <extension vendor-name="kodo" key="data-column" value="MEMO_COLUMN" /> <extension vendor-name="kodo" key="column-length" value="-1" /> </field> <field persistence-modifier="transactional" null-value="exception" default-fetch-group="true" embedded="true" name="name"> <extension vendor-name="kodo" key="data-column" value="NAME_DATA" /> </field> <field primary-key="true" name="pk1"> <extension vendor-name="kodo" key="column-length" value="10" /> </field> <field primary-key="true" name="pk2"> <extension vendor-name="kodo" key="column-length" value="20" /> </field> <field name="testMap"> <map key-type="String" embedded-key="false" value-type="Integer" /> <extension vendor-name="kodo" key="key-column" value="TEST_MAP_KEY" /> </field> </class> </package> </jdo>