cvs -d :pserver:guest@cvs.formdef.dev.java.net:/cvs checkout -P formdef
<plug-in className="formdef.plugin.FormDefPlugIn"> <set-property property="pathnames" value="/WEB-INF/form-defs.xml"/> </plug-in>Note: FormDef supports a standalone XML format and a combination XML format which you can use to combine form definitions and form validations. The combination XML format is useful if you use the Validator plugin and would like to keep the definition and validation information in one place. For more information, see Combining FormDef and Validator configuration.
<form-definition> <formset> <form name="myForm" beanType="com.my.dto.MyBean"/> </formset> </form-definition>When the plugin gets executed, it will create a DynaActionForm containing String fields for each property of MyBean. The JavaBeans specification is used to identify the fields that MyBean has. For fields that do not follow the JavaBeans specs, see Specifying field accessor methods.
<form-definition> <formset> <form name="myForm" beanType="com.my.dto.MyBean" formType="org.apache.struts.validator.DynaValidatorForm"/> </formset> </form-definition>To change the default type used for all form beans, add a formdef-config element:
<form-definition> <formdef-config formType="org.apache.struts.validator.DynaValidatorForm"/> <formset> ... </formset> <form-definition>The global declaration changes the default type. Individual form beans can still specify a different formType as needed.
FormUtils.getFormValues()
to convert the form bean
to a business object, the default behavior is to use the business object's
no-arg constructor. This behavior can be changed by specifying a class that
will act as a factory for your business object:
<form name="personForm" beanType="com.my.dto.Person"> <factory type="com.my.dto.PersonFactory" method="getPerson" nameParam="true"/> ... <form/>For the above example, when FormUtils needs an instance of personForm, it will call the getPerson method of the PersonFactory class and pass it the name of form bean as the parameter. Note that PersonFactory doesn't need to implement any interface and the actual method can be given any name. The factory method may or may not accept parameters, and in the case where it does, it has to be a single String identifying the name of the form bean to be instantiated. The return value must be an instance of the business object for that form bean.
<form name="sampleForm" beanType="com.my.dto.SampleBean"> <field property="specialDate" getter="getLastSpecialDate" setter="addSpecialDate"/> </form>In the above example, a
specialDate
field is added to the form
bean declaration. During formatting and parsing operations, the getLastSpecialDate
method is called to retrieve the current specialDate, and addSpecialDate
is
called to pass the value from the form bean to the business object.
<form name="sampleForm" beanType="com.my.dto.SampleBean"> <field property="selectedButton"/> </form>The above example will add a selectedButton field in the
sampleForm
form bean, along with the fields from SampleBean
.
java.util.String
by default.
This can be overridden by providing a type attribute to a field.
<form name="memberForm" beanType="com.my.dto.Member"> <field property="inactive" type="java.lang.Boolean"/> </form>
<form name="memberForm" beanType="com.my.dto.Member"> <excludes>createDate, updateDate</excludes> </form>In the example above, the
createDate
and
updateDate
fields of Member
will not
have corresponding fields on memberForm
. Fields
listed in an <excludes> element will not be included on the
form even when there is a <field> element configured for it.
Optionally, a field can be configured for exclusion using the
exclude
attribute of <field> element.
<form name="memberForm" beanType="com.my.dto.Member"> <field property="createDate" exclude="true"/> <field property="updateDate" exclude="true"/> </form>
<field property="doubleField"> <converter param="###,###,##0.000"/> </field> <field property="dateField"> <converter param="yyyy-MM-dd"/> </field>Numeric data can be handled without specifying a format String. Date fields, on the other hand, require format Strings and one should always be provided when a form contains any type of Date object. Global converters can be used to specify field formats that can be used for all forms.
form-defs.xml
file.
Instead of specifying the param
attribute, a key
attribute can be given instead. Message format strings can also be
placed in a separate resource bundle. These formats can be specified
by using the bundle
attribute.
<field property="doubleField"> <converter key="currencyFormat"/> </field> <field property="dateField"> <converter key="dateFormat" bundle="bundle2"/> </field>In the example above, the
currencyFormat
key is used to
find the format to be applied for the doubleField property of the form.
For the dateField property, the dateFormat
key is used
on the the bundle2
resource bundle.
Specifying conversion formats this way allows an application supporting
multiple locales to adjust the data format used for each locale.
<form-definition> <global-converters> <global-converter for="property-type" target="java.util.Date" param="MM/dd/yyyy"/> </global-converters> </form-definition>With the above declaration, FormDef would use the "MM/dd/yyyy" string to format and parse all Date fields. Another use would be to declare a conversion class to use for a custom field type:
<global-converter for="property-type" target="formdef.plugin.example.employee.business.EmploymentCode" type="formdef.plugin.example.employee.web.EmploymentCodeConverter"/>The above declaration would use the EmploymentCodeConverter class to convert all fields that have the EmploymentCode type.
<global-converter for="converter-name" target="salary" param="###,###,##0.00"/>The above declaration would format all
salary
fields in all forms using
the ###,###,##0.00
format string.
<global-converter for="converter-name" target="salaryConverter" param="###,###,##0.00"/>The above global-converter entry declares a converter configuration with the name "salaryConverter". This converter can be associated with fields in form declarations:
<form name="sampleForm" beanType="com.my.dto.SampleBean"> <field property="desiredSalary"> <converter name="salaryConverter"/> </field> </form>
<!-- here's our configuration for the Address bean --> <form name="addressForm" beanType="my.package.Address"/> <form name="employeeForm" beanType="my.package.Employee"> <!-- specify that our address field should use addressForm --> <field property="address" formName="addressForm"/> </form>Internally, a special type of converter,
FormConverter
,
is associated with the field, and uses the form name as conversion
parameter to find the FormDef mapping.
FormCollectionConverter
implementation
as this field's converter.FormCollectionConverter
<!-- here's our configuration for the Address bean --> <form name="addressForm" beanType="my.package.Address"/> <-- (1) --> <form name="employeeForm" beanType="my.package.Employee"> <!-- specify that our address field should use ArrayList --> <field property="address" type="java.util.ArrayList"> <-- (2) --> <converter type="formdef.plugin.conversion.FormCollectionConverter" <-- (3) --> param="addressForm"/> <-- (4) --> </field> </form>The
AddressConverter
is an implementation
of the FormDef-provided FormCollectionConverter
which
will loop through the collections of the bean and create their
counterpart forms, and vice versa, during conversion.
When creating the collection for either the bean or the form,
FormCollectionConverter
will use the declared type
for the field to instantiate a Collection. In the example above,
the "address" Collection will be set to an instance of
"java.util.ArrayList". Similarly, on the
my.package.Employee
bean, its "address" Collection
will be set to an instance of its declared type.
If the declared types on either the form or the bean are abstract
classes, such as java.util.List or java.util.Set, additional
properties can be configured to specify which implementation
class will be used for the field.
<form name="employeeForm" beanType="my.package.Employee"> <field property="address" type="java.util.List"> <converter type="formdef.plugin.conversion.FormCollectionConverter" param="addressForm"> <set-property key="formType" value="java.util.ArrayList/> <set-property key="beanType" value="java.util.ArrayList/> </converter> </field> </form>
In the example above, "address" is declared as the abstract class "java.util.List", with the "formType" converter property is used to tell FormCollectionConverter which List implementation to instantiate.
Likewise, the my.package.Employee
object may itself
declare its "address" field to be an abstract class such as
"java.util.List" or even "java.util.Collection". The "beanType"
converter property is then used to indicate which concrete class to
use when populating this field.
FormUtils.setFormValues()
can be used to initialize a form bean
with values from a business object:
DynaActionForm dynaForm = (DynaActionForm) FormDefUtil.setFormValues("employeeForm", employee, this, mapping, request);The first parameter identifies the form definition that will be used.
FormUtils.setFormValues()
returns the populated form bean.
This can then be placed by the caller in the proper scope with the proper
name so that Struts can find it when rendering an HTML form.
FormUtils.getFormValues()
can be used to create a populated business object
from a form bean:
Employee employee = (Employee) FormDefUtil.getFormValues(form, this, mapping, request);The first parameter is the form passed by Struts to the action object.
getFormValues()
returns the business object populated with
values from the form bean. If a factory is associated with the form
definition, it is called to create the business object that will be populated.
Otherwise, the business object's no-arg constructor will be used to create
the object.
setFormUtils()
and getFormUtils
. These can be
used for more control in the formatting and parsing of form data.
Consult the FormUtils class for more details.
setFormUtils()
and
getFormUtils
are implemented by instance methods
that can be overridden. To accomplish this, a FormUtils
subclass can be provided with the overriding method implementations.
A FormUtilsFactory implementation must be provided to return
the FormUtils subclass that should be used.
The register the custom FormUtilsFactory
implementation,
the formUtilsFactory
attribute of the
formdef-config
element is provided:
<form-definition> <formdef-config formUtilsFactory ="com.my.FormUtilsFactory"/> ... <form-definition>
<form-definition> <formdef-config formType="org.apache.struts.validator.DynaValidatorForm"/> <global-converters> <global-converter for="property-type" target="java.util.Date" param="MM/dd/yyyy"/> </global-converters> <formset> <form name="employeeForm" beanType="formdef.plugin.example.employee.business.Employee"> <field property="salary"> <converter param="###,###,##0.000"/> </field> </form> </formset> </form-definition>The above example declares that the DynaValidatorForm should be used as the default form type. It also declares a global format string for Date fields, and declares an
employeeForm
with a format string for the
salary
field.
Here's the validation config for the form:
<form-validation> <form name="employeeForm"> <field property="birth" depends="required,date"> <arg0 key="employeeform.birth.displayname"/> <var> <var-name>datePatternStrict</var-name> <var-value>MM/dd/yyyy</var-value> </var> </field> <field property="salary" depends="required,mask"> <arg0 key="employeeform.salary.displayname"/> <var> <var-name>mask</var-name> <var-value>^(?:\d+|\d{1,3}(?:,\d{3})*)(?:\.\d{1,2}){0,1}$</var-value> </var> </field> </form> </form-validation>The above config validates that the
birth
and salary
fields have the right format. Combining the two configurations, we have:
<form-definition> <formdef-config formType="org.apache.struts.validator.DynaValidatorForm"/> <global-converters> <global-converter for="property-type" target="java.util.Date" param="MM/dd/yyyy"/> </global-converters> <formset> <form name="employeeForm" beanType="formdef.plugin.example.employee.business.Employee"> <field property="birth" depends="required,date"> <arg0 key="employeeform.birth.displayname"/> <var> <var-name>datePatternStrict</var-name> <var-value>MM/dd/yyyy</var-value> </var> </field> <field property="salary" depends="required,mask"> <converter param="###,###,##0.000"/> <arg0 key="employeeform.salary.displayname"/> <var> <var-name>mask</var-name> <var-value>^(?:\d+|\d{1,3}(?:,\d{3})*)(?:\.\d{1,2}){0,1}$</var-value> </var> </field> </form> </formset> </form-definition>The <global-converter> remains as is, and that's because there's no equivalent in Validator. The form declaration now combines the definition and validation information. The <form> has the bean-name attribute for FormDef. The <field>s have the depends attribute for Validator, the <converter> element for FormDef, and the <arg0>, and <var> elements for Validator. Be aware that properties of the
Employee
class that do not have
validation rules will not be validated but are still declared in the resulting
form bean.
This example is based on the Employees example application.
<plug-in className="formdef.plugin.validator.CombinedFormDefPlugIn"> <set-property property="pathnames" value="/WEB-INF/form-defs-validator-employees.xml"/> </plug-in> <plug-in className="formdef.plugin.validator.CombinedValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/form-defs-validator-employees.xml"/> </plug-in>Notice that the CombinedValidatorPlugIn is also passed the
validator-rules.xml
which contains the standard declarations that come with the Validator plug-in. It can
accept existing validator.xml files that are using the default Validator DTD as well as
those containing the combined format.
validate=false
in a form or field's declaration.
<form name="mySimpleForm" beanType="com.my.dto.MySimpleBean" validate="false"> <field name="someField"/> </form> <form name="myOtherForm" beanType="com.my.dto.MyOtherBean> <field name="someField" depends="required"/> <field name="selectedButton" validate="false"/> </form>In the example given above,
mySimpleForm
configures a form
bean definition but specifies that it should not be passed to the Validator engine.
A second form, myOtherForm
, has one field that requires validation,
someField
. Its associated business object may contain several other
fields, and FormDef will create a form bean which contains all those fields.
Because those fields aren't declared here, Validator will not "see" those other fields.
However, an additional field, selectedButton
, is being added to the form
bean. To prevent Validator from "seeing" this field, validate=false
is added to its declaration.
generate=false
in a form's declaration.
<form name="myExistingForm" generate="false"> ... </form>In the example given above,
myExistingForm
defines validation rules
for a similarly named form. The generate=false
attribute will
tell the CombinedFormDefPlugIn not to generate a form bean for this form,
which could be defined in struts-config.xml or is a ValidatorActionForm
subclass.