The “Issue” thing is a joke. I don’t know what else to call this. I’ve been thoroughly enjoying the last couple weeks I’ve been spending with Struts, I learn something new everyday. One of the things that I happened upon today was a tip from Ted Husted buried deep in his overview of Struts design patterns and strategies page (a great resource btw) which suggests using the LabelValueBean as a core value object class:
When a good number of drop-down controls are being used, standardize on the LabelValueBean object provided in the Struts example. This is an easy way to create both the Label and Value collections the Struts options tag expects.
One of the things that I really like about Struts is the strict separation between presentation, business logic and model. I’ll spend a couple hours writing Action classes, some ActionForms, maybe a utility class or two and then switch over to implementing the JSP using JSTL (and very little time working with the model since I’m using Hibernate, but that’s anothe post). I’m never writing directly to the response with the Action classes, the ActionForms, etc… all of the presentation is done using JSP. The JSP’s become so much more simple. The first couple sites I wrote using servlets & JSP were (and for the most part still are) a complete mishmash of JSP’s with embedded SQL, buggy tags, and scriplets. With Struts, for the most part you don’t have to use scriptlets, you’re left with clean template-like code that the Actions provide data for.
So now I’ve come full circle. The LabelValueBean is an example of the data that the Actions provide to the JSP’s and they become a very useful tool when you’ve got to populate month select boxes, year select boxes, state select boxes, etc., etc. This morning I started out by creating a Month bean (which had only label and value properties), a Year bean (with only label and properties) , and so on… a definite trend. I created a factory class that handled the creation of those beans and returned a collection to the Action instance, which then put the collection into a request attribute for retrieval by the JSP. The code looked something like this:
// code in the factory class
public static Collection getYears() {
Calendar c = Calendar.getInstance();
Collection years = new ArrayList();
int year = c.get(Calendar.YEAR);
int endyear = year + 10;
for (int i=year; i<endyear; i++) {
years.add(new Year(String.valueOf(i), String.valueOf(i)));
}
return years;
}
// code in the Action class
Collection years = YearFactory.getYears();
request.setAttribute("years", years);
// code in the JSP
<html:select property="payment_year">
<html:options collection="years" property="value" labelProperty="label" />
</html:select>
There are a couple things in the above code that can be improved. First, like I mentioned before, I should have used the LabelValueBean instead of creating my own Year bean. Because the presentation is completely independent of the business logic, I need only change a single line of code (and an import for you sticklers out there). This:
years.add(new Year(String.valueOf(i), String.valueOf(i)));
becomes this:
years.add(new LabelValueBean(String.valueOf(i), String.valueOf(i)));
Next (at this point I should probably mention that I’ve been poring over Effective Java while exercising at night), performance savvy programmers probably winced at the number of unnecessary objects (Item #4) I’ll end up creating with the getYears() method. What I should have done instead was create the years collection and collection elements in a static constructor and store the result as a private static, returning the result when the getYears() method is called. So the above example is refactored to this:
private static Collection years = new ArrayList();
static {
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int endyear = year + 10;
for (int i=year; i<endyear; i++) {
years.add(new LabelValueBean(String.valueOf(i), String.valueOf(i)));
}
}
public static Collection getYears() {
return years;
}
Finally, a small touch that I learned (and am attempting to use faithfully) from Item #34, “Refer to objects by their interfaces.” In the code examples above I could have declared the return type and the private static to be an ArrayList:
// private static declaration
private static ArrayList years = new ArrayList();
// factory method
public static ArrayList getYears() {
Changing the implementation from an ArrayList to a Vector would have required changes to any of the classes that use this factory, which makes my program less flexible. Instead, using the Collection interface, my program becomes easier to use and to modify:
private static Collection years = new ArrayList();
// could also be this with no changes to the public API
private static Collection years = new Vector();
I’m always interested in your feedback! Thanks for listening.