The XDoclet Struts module supports creating and validating DynaForms through the use of a handful of XDoclet JavaDoc tags. It’s pretty simple, but some explanation is required to take full advantage of this feature. This short tutorial is mostly code, without much description of the various XDoclet tags you’ll see here. For a detailed description, please refer to the XDoclet site.
Let’s start out by looking at two separate classes, Person and Address. Person is shown first:
/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {
private Long id;
private String name;
private String notes;
private Address address;
public void setId(Long id) { this.id = id; }
public Long getId() { return this.id; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }
/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }
/**
* @struts.validator type="maxlength"
* @struts.validator-args arg0resource="person.notes"
* @struts.validator-args arg1value="${var:maxlength}"
* @struts.validator-var name="maxlength" value="4000"
*/
public void setNotes(String notes) { this.notes = notes; }
/**
* @struts.dynaform-field
*/
public String getNotes() { return this.notes; }
}
As you can see, Person is pretty simple - just a few properties and some comments. The associated Address class is shown below:
public class Address {
private String line1;
private String line2;
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
public String getLine1() { return this.line1; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }
public String getLine2() { return this.line2; }
}
Now that we have our two classes, let’s go over the various tags and what each one does, starting with the Person class.
/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {
The class-level XDoclet tags define that a DynaValidatorActionForm should be created in the struts-config.xml file, with a name of “personForm” and a type of “org.apache.struts.validator.DynaValidatorActionForm”. You can substitute your own type here if you want to subclass one of the ActionForm classes. If you want to also generate the validation rules for your DynaForm, you have to include the ‘validate=”true”‘ attribute. This attribute just aids processing by the XDoclet templates; it’s not included in the output files. After the class-level comments, we have the various method-level comments. We’ll start with the name attribute in the Person class.
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }
The above code is a simple setter and getter pair. What makes this attribute interesting are the comments that generate the valication rules and the form property. Starting with the setter, we can see that the name property is required when the user submits the DynaForm. If the name property is omitted, the “person.name” value is retrieved from the resource bundle. It’s probably best to look at the generated portion of the validation.xml file to understand what’s going on here:
<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>
...
</form>
As you can see, it’s pretty simple to define the validation rules use XDoclet tags. Of course, we also need to define our form fields. The getter method has the relevant XDoclet tag to create a form-property element in our struts-config.xml. As shown, the struts.dynaform-field tag will just create the following XML snippet:
<form-property name="name" type="java.lang.String"/>
The name and type attributes are taken from the method. Of course, we don’t have to use the defaults. We can specify a different name and type if we want, as well as define multiple form fields in the getter. For example:
/**
* @struts.dynaform-field
* name="firstName"
* type="java.lang.String"
* @struts.dynaform-field
* name="lastName"
* type="java.lang.String"
*/
public String getName() { return this.name; }
This feature is handy when you need to add additional form fields, but don’t need to define additional object attributes. Let’s look at what our complete form definition for the struts-config.xml would look like:
<form-bean name="personForm" type="org.apache.struts.validator.DynaValidatorActionForm">
<form-property name="name" type="java.lang.String"/>
<form-property name="address" type="example.Address"/>
<form-property name="notes" type="java.lang.String"/>
</form-bean>
What about that Address class? We haven’t talked about it yet. We’re not concerned about creating a DynaForm representation of it, although we could rather easily. Instead, the personForm will just have an instance of the Address class and will access it as a nested bean. We’re more concerned about validating the properties of the Address class when the user submits a personForm. Let’s revisit the Address property in the Person class:
/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }
You can see that the setter for the Address only has a simple struts.validator tag. That tells the XDoclet template to look in the Address class for all of the validation definitions:
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
...
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }
The XDoclet template follows the struts.validator rule in the Person class to the Address class and includes whatever it finds there. The final result of these rules is the following validation.xml snippet for the personForm:
<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>
<field
property="notes"
depends="maxlength">
<arg0
key="person.notes"
/>
<arg1
key="${var:maxlength}"
resource="false"
/>
<var>
<var-name>maxlength</var-name>
<var-value>4000</var-value>
</var>
</field>
<field
property="address.line1"
depends="required">
<arg0
key="address.line1"
/>
</field>
<field
property="address.line2"
depends="required">
<arg0
key="address.line2"
/>
</field>
</form>
Next, we need to look at the Ant tasks to generate these files. An annotated XML snippet is shown below.
<target name="xdoclet-web">
<taskdef classname="xdoclet.modules.web.WebDocletTask" classpathref="project.class.path" name="webdoclet"/>
<webdoclet destDir="etc/web" excludedTags="@author,@version,@todo" mergeDir="etc/merge">
<fileset dir="src">
<include name="**/*.java"/>
</fileset>
<!-- The strutsconfigxml element generates the struts-config.xml file. -->
<strutsconfigxml destDir="etc/web" mergeDir="etc/merge" version="1.1"/>
<!-- By including this element, the validation.xml file will be
generated based on your struts.validation tags. -->
<strutsdynaformvalidationxml/>
</webdoclet>
</target>
That’s all there is to creating and validating your DynaForm with XDoclet. A future revision to this tutorial will include a method to override the validation rules defined in an associated objects.
nick Articles