DynaForm s: Forms Without Java


DynaForm s: Forms Without Java

DynaForm s are an extension of the Apache Commons Beanutils project. As part of the org.apache.commons.beanutils package, an interface called DynaBean was created. Unlike normal JavaBeans, which require explicit get XXX () and set XXX () methods to be written for each property, a DynaBean uses a generic get() and set() method with the property name as the first argument.

A fuller description of the DynaBean package can be found on the Jakarta Web site at http://jakarta.apache.org/commons/beanutils.html.

For example, in a traditional JavaBean, you would say

 myBean.setType("kidneybean"); 

Using DynaBean s, you would say

 myBean.set("type", "kidneybean"); 

This approach has both advantages and disadvantages. The major advantage is that you don't have to declare all your properties explicitly at compile-time; they can be loaded dynamically during execution. This can be very handy to quickly create new beans or new properties of beans.

The disadvantage is that you lose a lot of compile-time error checking. Let's say you are thick-fingered, and enter

 myBean.set("tpye", "kidneybean"); 

The compiler won't catch this. As far as it's concerned , this is perfectly legal Java. It's not until run-time that you'll suddenly find yourself with a null pointer exception. Similarly, all get() and set() methods take and return the Object type, so you lose the strong type-checking of traditional beans.

DynaBeans and Struts

One place that DynaBeans make a lot of sense is in Struts. If you use DynaBeans correctly, you can reduce the size of your ActionForm s by 80 “90%. This is because you can use DynaBeans to eliminate all of your form getters and setters.

To see how this works, you'll rewrite the two ActionForm s for the new account pages of the StockTrack application. To begin, take a look at one of the existing ActionForm s and the same form rewritten with DynaForm s (Listing 17.1 and 17.2).

Listing 17.1 NewUserAddressForm.java
 package stocktrack.struts.form; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionForm; import stocktrack.struts.form.BaseForm; /**  * stocktrack.struts.form.NewUserAddressForm class.  * this class used by Struts Framework to store data from newUserAddressForm  *  * struts-config declaration:  * <form-bean name="newUserAddressForm"  *         type="stocktrack.struts.form.NewUserAddressForm" />  *  * @see org.apache.struts.action.ActionForm org.apache.struts.action.ActionForm  * Generated by StrutsWizard.  */ public class NewUserAddressForm extends BaseForm {   public void reset(ActionMapping mapping, HttpServletRequest request) {     streetAddress1 = "";     streetAddress2 = "";     city = "";     state = "";     postalCode = "";     homePhone = "";     workPhone = "";     workExt = "";   }   public ActionErrors validate(ActionMapping mapping,                                HttpServletRequest request) {     ActionErrors errors = new ActionErrors();     if (this.isBlankString(streetAddress1)) {         errors.add("streetAddress1",                    new ActionError("stocktrack.newuser.required"));     }     if (this.isBlankString(city)) {         errors.add("city", new ActionError("stocktrack.newuser.required"));    }     if (this.isBlankString(state)) {         errors.add("state", new ActionError("stocktrack.newuser.required"));    } else {       if (!this.isValidState(state)) {         errors.add("state",                    new ActionError("stocktrack.newuser.invalid.state"));       }    }     if (this.isBlankString(postalCode)) {         errors.add("postalCode",                     new ActionError("stocktrack.newuser.required"));    } else {      if (!this.isValidPostalCode(postalCode)) {          errors.add("postalCode",                     new ActionError("stocktrack.newuser.invalid.postalCode"));      }    }    if (this.isBlankString(homePhone)) {        errors.add("homePhone", new ActionError("stocktrack.newuser.required"));    } else {        if (!this.isValidPhone(homePhone)) {          errors.add("homePhone",                     new ActionError("stocktrack.newuser.invalid.phone"));        }    }    if (this.isBlankString(workPhone)) {        errors.add("workPhone", new ActionError("stocktrack.newuser.required"));    } else {        if (!this.isValidPhone(workPhone)) {          errors.add("workPhone",                     new ActionError("stocktrack.newuser.invalid.phone"));        }    }    return errors;  }  private String streetAddress1;  private String streetAddress2;  private String city;  private String state;  private String postalCode;  private String homePhone;  private String workPhone;  private String workExt;  public String getStreetAddress1() {    return streetAddress1;  }  public void setStreetAddress1(String streetAddress1) {    this.streetAddress1 = streetAddress1;  }  public String getStreetAddress2() {    return streetAddress2;  }  public void setStreetAddress2(String streetAddress2) {    this.streetAddress2 = streetAddress2;  }  public String getCity() {    return city;  }  public void setCity(String city) {    this.city = city;  }  public String getState() {    return state;  }  public void setState(String state) {    this.state = state;  }  public String getPostalCode() {    return postalCode;  }  public void setPostalCode(String postalCode) {    this.postalCode = postalCode;  }  public String getHomePhone() {    return homePhone;  }  public void setHomePhone(String homePhone) {    this.homePhone = homePhone;  }  public String getWorkPhone() {    return workPhone;  }  public void setWorkPhone(String workPhone) {    this.workPhone = workPhone;  }  public String getWorkExt() {    return workExt;  }  public void setWorkExt(String workExt) {    this.workExt = workExt;  } } 
Listing 17.2 NewUserAddressForm.java as a DynaForm
 package stocktrack.struts.form; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionForm; import stocktrack.struts.form.BaseForm; import stocktrack.struts.form.BaseDynaForm; /**  * stocktrack.struts.form.NewUserAddressForm class.  * this class used by Struts Framework to store data from newUserAddressForm  *  * struts-config declaration:  * <form-bean name="newUserAddressForm"  *         type="stocktrack.struts.form.NewUserAddressForm" />  *  * @see org.apache.struts.action.ActionForm org.apache.struts.action.ActionForm  * Generated by StrutsWizard.  */ public class NewUserAddressForm extends BaseDynaForm {   public ActionErrors validate(ActionMapping mapping,                                HttpServletRequest request) {     ActionErrors errors = new ActionErrors();     if (BaseForm.isBlankString(this.getString("streetAddress1"))) {         errors.add("streetAddress1",                    new ActionError("stocktrack.newuser.required"));     }     if (BaseForm.isBlankString(this.getString("city"))) {         errors.add("city",                    new ActionError("stocktrack.newuser.required"));    }     if (BaseForm.isBlankString(this.getString("state"))) {         errors.add("state", new ActionError("stocktrack.newuser.required"));    } else {       if (!BaseForm.isValidState(this.getString("state"))) {         errors.add("state",                     new ActionError("stocktrack.newuser.invalid.state"));       }    }     if (BaseForm.isBlankString(this.getString("postalCode"))) {         errors.add("postalCode",                    new ActionError("stocktrack.newuser.required"));     } else {       if (!BaseForm.isValidPostalCode(this.getString("postalCode"))) {           errors.add("postalCode",                      new ActionError("stocktrack.newuser.invalid.postalCode"));       }     }     if (BaseForm.isBlankString(this.getString("homePhone"))) {         errors.add("homePhone", new ActionError("stocktrack.newuser.required"));     } else {         if (!BaseForm.isValidPhone(this.getString("homePhone"))) {           errors.add("homePhone",                      new ActionError("stocktrack.newuser.invalid.phone"));         }     }     if (BaseForm.isBlankString(this.getString("workPhone"))) {         errors.add("workPhone", new ActionError("stocktrack.newuser.required"));     } else {         if (!BaseForm.isValidPhone(this.getString("workPhone"))) {           errors.add("workPhone",                      new ActionError("stocktrack.newuser.invalid.phone"));         }     }     return errors;   } } 

The first thing to notice here is that the class has been changed from BaseForm (which, as you might recall, is simply ActionForm with a few helper functions added for validation) to BaseDynaForm , which is a different helper class that extends DynaActionForm instead. All the getters and setters have been removed, and the validate function now uses this.getString to get the values of the properties rather than accessing the local variables of the class.

getString() is in fact not a part of DynaActionForm , which only defines generic get() and set() methods that take and return Object s. However, rather than cast to String all the time, I've created BaseDynaForm , which adds the getString() versions. Listing 17.3 shows this simple class.

Listing 17.3 BaseDynaForm.java
 package stocktrack.struts.form; import org.apache.struts.action.DynaActionForm; public class BaseDynaForm extends DynaActionForm {   public String getString(String name) {     return (String) this.get(name);   }   public String getString(String name, int ind) {     return (String) this.get(name, ind);   } } 

In addition, now that the class no longer derives from BaseForm , you need to call out explicitly to BaseForm to get helper functions such as nullOrVoid . Because they were originally defined nonstatic, you must go into BaseForm and declare them static. I suppose that we could have copied the code from BaseForm to BaseDynaForm , but that would have meant maintaining the same code in two places.

The <form-property> Tag

So, if all the getters and setters have been removed from the class, how does the class know what its legal properties are? The answer lies in the form-bean tag in struts-config.xml .

Until now, the forms you've defined in the file looked like this:

 <form-bean name="newUserAddressForm"            type="stocktrack.struts.form.NewUserAddressForm" /> 

But now, you're going to add some new tags, form-property tags, to the form-bean (see Listing 17.4).

Listing 17.4 The Rewritten newUserAddress Form
 <form-bean name="newUserAddressForm" type="stocktrack.struts.form.NewUserAddressForm">   <form-property name="streetAddress1" type="java.lang.String"/>   <form-property name="streetAddress2" type="java.lang.String"/>   <form-property name="city" type="java.lang.String"/>   <form-property name="state" type="java.lang.String"/>   <form-property name="postalCode" type="java.lang.String"/>   <form-property name="homePhone" type="java.lang.String"/>   <form-property name="workPhone" type="java.lang.String"/>   <form-property name="workExt" type="java.lang.String"/> </form-bean> 

Inside the form-bean , all the properties have been listed along with their type. This allows the DynaForm to populate the fields. You can use pretty much any class you want in the type value, as well as primitives such as int , Boolean , and so on.

You can also specify initializations for properties via the initial keyword. For example, the following form-property sets up a property called opt-in , which defaults to true:

 <form-property name="homePhone" type="boolean" initial="true"/> 

The initial keyword is also the only way to create an array or list of a given size. Imagine that you have a form with 10 lines to fill in the names , ages, and genders of the user 's dependents. You'd define it like so:

 <form-property name="depName" type="java.lang.String[]"    initial="{'','','','','','','','','',''}"/> <form-property name="depAge" type="java.lang.String[]"    initial="{'','','','','','','','','',''}"/> <form-property name="depGender" type="java.lang.String[]"    initial="{'','','','','','','','','',''}"/> 

Whatever the type requested , if you want to specify an initial value, there must be a converter defined from String to that class in the Commons Beanutils package. You can add your own converters, so just about any class can be initialized via a form-property tag.

String (and other) arrays are accessed using get() and set() , the same as any other DynaBean . However, you use a second argument, which specifies the index into the array.



Struts Kick Start
Struts Kick Start
ISBN: 0672324725
EAN: 2147483647
Year: 2002
Pages: 177

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net