Using Generics and a Form with Wicket

This blog post I will take a look at using a form with Wicket and binding it to an object using a PropertyModel along with Generics. I just started digging into generics in Java and even after reading a tutorial on generics, the use of <T> and the wildcard value <?> still is not completely clear to me. Yet, I think with use of Wicket, it will help my understanding and hopefully yours too. Enough fluff, I shall get to the details. The Generics add type safety and eliminate the need for casting as was originally done in the book example.

The example code for this blog can be downloaded. This sample code is once again built upon the examples used in the book titled Wicket in Action by Dashorst et al. The project is Maven, so if you have the Maven Plugin for your Eclipse, download the file, unzip it, and import the File->Import->Existing Projects into Workspace. The project name is hippo02. For this project, it has a Form and, the Customer class which along with its attributes is also composed of the Address class. The form has the coresonding html:

<form wicket:id="myform">
<table>
<tr><td>Name</td><td><input type="text" wicket:id="name" /></td></tr>
<tr><td>Street</td><td><input type="text" wicket:id="street" /></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>

The form contains the wicket identifier myform for the form along with two other identifiers for the text fields: wicket:id=”name” and wicket:id=”street”

The two following snippets detail the classes involved: Customer and Address. A Customer has an Address. First, the Customer class. Note that the class must be made serializable so that Wicket can save state. I omitted the getters and setters. Check the hippo source if you want to see them. Next, I created the Form1 specifying the generic parameter <Customer>. So, when the object model is fetched as can be seen in the onSubmit method, the type does not need to be cast. Now, I was a little uncertain about the TextField portions, but it seems that they should be set as <String> parameters. The part that I find somewhat confusing is the specifying the class attribute and the attribute for the text field. In the Form1 class, you will note that it specifies “firstName” in the property model, and then when the TextField is created using the just created property model, it uses the value “name” that matches the wicket:id attribute given in the html.

Now that this is all created, a Form1 object is created in the Index.java class and bound to the wicket:id attribute name “myform”.

This is what happens when the program is run. When a Form1 is created in Index.java, a Customer object is created. When the user enters values and presses submit, the onSubmit callback action sets the values entered into the two fields.

The plumbing seems a little tricky here, but I thought by breaking out these Anonymous Inner Classes (AIC) it would help break the details for the form. Plus, if you see a correction on the use of Generics, let me know. I hope this helps illustrate the use of PropertyModel and a Wicket Form<T>.

Customer class:

public class Customer implements Serializable {
  private String firstName;
  private String lastName;
  private Address address = new Address();

  //[snip]
}

Address class:

public class Address implements Serializable {
  private String name;
  private String street;
  private String city;
  private Integer zipcode;

  // [snip]
}

Form class:

public class Form1 extends Form<Customer> {

 private static final long serialVersionUID = 1L;
 private TextField<String> nameField;
 private TextField<String> streetField;
 private PropertyModel<String> namePropModel;
 private PropertyModel<String> streetPropModel;
 private Model<Customer> myModel;
 
 public Form1(String id) {
 super(id);
 
 Customer customer = new Customer();
 myModel = new Model<Customer>(customer);
 setModel(myModel);
 
 namePropModel = new PropertyModel<String>(customer, "firstName");
 nameField = new TextField<String>("name",namePropModel);
 add(nameField);
 
 streetPropModel = new PropertyModel<String>(customer, "address.street");
 streetField = new TextField<String>("street", streetPropModel);
 add(streetField);

 }
 
 protected void onSubmit() {
 Customer customer =  getModelObject();
 String street = customer.getAddress().getStreet();
 // do something with/to the customer
 }

}

Inclusion into Index.java:

Form1 myForm = new Form1("myform");
add(myForm);

About Brian Lavender

I like to program in C++, Java, and Pascal. I have an admiration for languages like Pascal, Ada, and Eiffel. I work a lot with GNU/Linux systems.
This entry was posted in Wicket. Bookmark the permalink.