ignore

Data Binding and Type Conversion Annotations

Data Binding Annotations

Strecks currently comes with two data binding annotations:

These are described in a bit more detail below.

@BindSimple

The usage of @BindSimple is shown below from an ActionForm subclass implementation.

private HolidayBooking booking;

private String days;

@BindSimple(expression = "booking.days")
public String getDays()
{
    return days;
}

@ValidateInteger(key = "holidaybookingform.days.number")
public void setDays(String days)
{
    this.days = days;
}

The booking object is the domain object which contains an Integer property called days. The expression booking.days is used to reference this property and hence perform the binding. Under the covers, the Jakarta Commons BeanUtils library is used, as it is elsewhere in Struts.

Note that a type conversion needs to take place to allow this data binding. @BindSimple has a converter attribute which by default is set to SafeBeanUtilsConverter. This converter implementation, which also uses Jakarta Commons BeanUtils, is able to perform the simple necessary type conversion without any additional configuration. The equivalent "longhand" way of expressing this is shown below:

@BindSimple(expression = "booking.title", 
    converter = SafeBeanUtilsConverter.class)
public String getDays()
{
    return days;
}

More advanced conversion requirements may require either a custom Converter implementation or even a custom converter annotation.

Data binding is bi-directional. An inward binding is a binding from form property to domain object and an outward binding is in the reverse direction. Inward bindings will take place when a form is submitted. Outward bindings take place when a form is rendered, but only if there are no form errors present. In this case, the form needs to be re-rendered with the user supplied values present. Also, note that the form's domain object must be populated before binding can occur. If necessary, this can be done in the form submission controller's preBind() method, if necessary.

JSP Markup

The JSP markup for using the @BindSimple annotation is very simple. Any Struts tag which maps directly to a single property value, such as html:text and html:textArea, can be used. An example is shown below:

<html:text property="days" size="2" />

@BindSelect

The purpose of @BindSelect is to allow for binding of user selections. Suppose our HolidayBooking object also contained a property leaveType of type LeaveType, which could be "annual vacation", "sickness" (OK, not really a holiday) or "personal day". This could be represented in the database using a reference data table, and presented on the user interface using a drop down menu or set of radio buttons.

An example of form implementing a @BindSelect in this case is shown below:

private Collection<LeaveType> leaveTypes;

private HolidayBooking booking;

private String selectedLeaveType;

@BindSelect(targetBeanExpression = "booking.leaveType", 
    lookupMapExpression = "leaveTypes", 
    targetBeanIdProperty = "leaveTypeId", 
    idClass = Integer.class)
public String getSelectedLeaveType()
{
    return selectedLeaveType;
}

public void setSelectedLeaveType(String selectedLeaveType)
{
    this.selectedLeaveType = selectedLeaveType;
}

public Collection<LeaveType> getLeaveTypes()
{
    return leaveTypes;
}

public void setLeaveTypes(Collection<LeaveType> leaveTypes)
{
    this.leaveTypes = leaveTypes;
}

In the example we see the ingredients required for a @BindSelect operation.

  1. The action form needs a String property which records the selection. This property is selectedLeaveType.
  2. The action form contains a property populated with the available leave types to make the selection from. This property is used to populate the user interface using the <html:optionsCollection/> or <html:radio/> tags, for example. In our example, the property is named leaveTypes and is a java.util.Collection, which could represent a List or Set. It could also be implemented as a java.util.Map, although the JSP markup would need to change to accommodate this. Typically, the collection property will also be accessible via the form, and will need to be populated, usually using some code in the action bean, before the page containing the form is rendered.
  3. The domain property needs to have a field of type LeaveType to hold the selection. In our example, this property is called leaveType.

When doing an inward binding in our example, the @BindSelect operation will:

Doing an outward binding is slightly simpler. Here, it goes throught the following steps:

The @BindSelect works well for reference data, which often has a numerical ID as well as a name field and other descriptive information attached.

JSP Markup

The last piece of the puzzle is the JSP markup. Below, we show two examples, one using a drop-down menu, and another using an HTML select. With the drop-down menu, we use the html:optionsCollection tag to present the options, shown below:

<html:select property="selectedLeaveType" size="1">
    <option value=""></option>
    <html:optionsCollection property="leaveTypes"
        label="leaveTypeName" value="leaveTypeId" />
</html:select>

In the radio button example, we iterate over leave types using the JSTL forEach tag. In our example, the value for the radio button will be the key for each Map entry iteration.

<c:forEach var="item" items="${holidayBookingForm.leaveTypes}">
    <c:set var="itemId" value="${item.leaveTypeId}" />
    <html:radio property="selectedLeaveType" 
        value="<%= pageContext.getAttribute("itemId").toString() %>" />
    <c:out value="${item.leaveTypeName}" /><br/>
</c:forEach>
Notice the use of the scriptlet in the html:radio tag. We could make this work slightly more elegantly by using the EL version of the Struts html:radio tag, in which case the above example would like as shown below:
<c:forEach var="item" items="${holidayBookingForm.leaveTypes}">
    <html-el:radio property="selectedLeaveType" 
        value="${item.leaveTypeId}" />
    <c:out value="${item.leaveTypeName}" /><br/>
</c:forEach>

Conversion Annotations

Much of the time, definining an explicit converter is not necessary. A notable exception is for date fields. In this case, a textual pattern must be identified which can be used to perform the conversion. For example, the JDBC Date object has the format yyyy-MM-dd. In this case, it is possible to parameterize the binding annotation with the converter class.

It would be a bit tedious, however, if a new converter class needed to be created for each date pattern which could be used. Strecks comes with a DatePaternConverter which is itself parameterized by the textual conversion pattern to be used. The problem with this class is that it cannot be used within the @BindSimple annotation, because @BindSimple defines no way of parameterizing converters. That's not its job.

This roles is instead performed by the @ConvertDate annotation. An example is shown below:

private String startDate;

@BindSimple(expression = "booking.startDate")
@ConvertDate(pattern = "yyyy-MM-dd")
public String getStartDate()
{
    return startDate;
}

Currently, the only supplied conversion annotation is the @ConvertDate annotation. However, the framework exists to create your own conversion annotations, allowing any custom converters to be parameterized as required.

SourceForge.net logo java.net Member logo Copyright © 2005-2007 Realsolve Solutions