Programming Thoughts
Struts 2 - Annotation-based Validation
Display Formatting
Improving a fix to a Struts 2 feature
Struts 2 is a popular MVC framework for Java-based web applications but its annotation-based validation doesn't properly work. So, an alternative was created but it has design limitations. This article considers a redesign to overcome them.
Bonus Feature
Though not an objective, semi-automatic formatting of view helpers, especially for search results, using the existing annotation and converters is an obvious idea. Source data for view helpers are typically Data Transfer Objects and are used, such as below.
public class ContentTypeDisplay extends AflDisplay { private String id; private String name; private String notes; private String watermark; private String deletedText; private boolean deleted; public ContentTypeDisplay(ContentTypeVO record) { if (record != null) { id = FormatUtil.formatNumber(record.getId()); name = record.getName(); notes = record.getNotes(); watermark = FormatUtil.formatFlag(record.getWatermark() != null && record.getWatermark().equalsIgnoreCase("Y")); deletedText = FormatUtil.formatFlag(record.getStatusId().intValue() == STATUS.DELETED); deleted = record.getStatusId().intValue() == STATUS.DELETED; } else { id = ""; name = ""; notes = ""; watermark = ""; deletedText = ""; deleted = false; } }
Data Transfer Objects are defined by a back-end, so won't have presentation layer annotations. Thus, annotations must be on view helper fields. As an Interceptor cannot know what source data a view helper needs or where to get it, the Action must call a library function.
Basic Algorithm
It would seem the basic algorithm is for each field of the record class, find the matching field of the display, find the annotated converter or default converter, then convert the record field value to the display field. Alas, array and collection fields complicate that. Re-using form field annotations means they should be consistent with their use in forms, meaning display fields can only be single string fields and source record fields can only be single fields or collections, as table below.
Record type | Destination type | Formatted |
---|---|---|
Single | Single | Yes |
Single | Array | |
Single | Collection | |
Array | Single | |
Array | Array | |
Array | Collection | |
Collection | Single | Yes |
Collection | Array | |
Collection | Collection |
This may seem of limited use but arrays or collections of simple values are rare as source records are from database tables conforming to First Normal Form. Collections are typically related records but the algorithm doesn't follow object graphs. That might be the subject of a future article.
Existing Converters Not Quite Useful
The format function of converters are meant for display to users, but quirks of UI means there are exceptions, especially when displaying in search result lists.
- Boolean - data entry of a boolean value is typically a checkbox and the converter uses '1'/'' but display can be 'Yes'/'No' or tick/cross characters. Such text can be made with a custom converter.
- Enumerated - data entry of a enumerated value is typically a dropdown or radio buttons but value names are block capitals as per Java convention. User friendly text can be made with a custom converter.
Next part
Continued in Redesign Evaluation.