Programming Thoughts
Struts 2 - Annotation-based Validation
Evaluation

Actually reducing Struts 2's arcane configuration

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. It should be evaluated against its design objectives.

Design Objectives

The Alternate Annotations page stated the objectives of the alternate design. Each will be evaluated.

Objective Notes
Interceptor based A new interceptor is declared in struts.xml and a new entry for any interceptor stack for Actions that receive forms.
Interceptor should be extensible This can only be judged by future extension attempts but the core algorithm calls many, protected functions.
Actual adjustment, validation and conversion should be separate classes
Annotation should use defaults where possible The following is a working example. Perhaps the repeated message is the only excess.

@Required(message= "Limit must be number between 10 and 500") @IntegerConversion(message= "Limit must be number between 10 and 500") @IntegerRange(min=10, max=500, message= "Limit must be number between 10 and 500")

Policies don't apply if the form field value isn't set.
Receiving form fields are character strings Pages display the original form fields whilst Actions access the converted values.
Converters should have a reverse conversion function for form formatting These are used in form formatting.
Form formatting should be automatic This is incompatible with existing code and the following code must be used.

formatForms();

Compatible with manual conversion and validation Form fields without annotations are ignored by the interceptor and the Action's validate function has not gone away.
Recognise ModelDriven As per standard behaviour, if the Action implements ModelDriven, the interceptor uses its model as the form, otherwise the Action is the form.
Annotation can configure that messages write to field errors, action errors or even action messages All annotations have a messageType parameter for this.
Abandon reliance on Struts UI tags
Configuration only in the form field annotations struts.xml for declaring the new interceptor and message resource files, if annotations use message keys, are the only separate files.
Custom conversion and validator annotations should be able to use code in the same form Custom annotations use class references to obtain custom validators and converters, which can even be inner classes. It would be better if lambda expressions could be used but annotations can't use them.
A block of code in converters and validators should be able to report one of many error messages

Implementation Notes

  • Hardcoded policies - As described in Alternate Interceptor, the set of recognised annotations is hardcoded. Although custom policies are easily written, client supplied annotations would still be better. This will be the subject of a future article.

Other Designs

Implementation of this idea grants better understanding of Struts 2 and consideration of other design ideas. First, a restatement of this idea, followed by other ideas.

  • String form fields - request parameters are received by string fields instead of those of the expected data type and a custom interceptor converts them in another set of fields.
  • Replacement data tags - use existing annotation-based conversion and validation but use custom tags instead of data tags that trip over rejected field values, such as s:date
  • Replacement parameters interceptor - whereas the standard parameters interceptor sets string form fields with no attempt at conversion, it does not ignore non-string form fields the alternate validator will convert, creating a conflicting set of conversion errors.
  • Custom tag checks form field annotations - use replacement annotation-based conversion and validation but use a custom tag to read form field values. If the value is a string, it's an expected string, or a rejected user input, otherwise the form field's annotation are read to use its converter to format.
  • Interceptor formats values to Value Stack - use replacement annotation-based conversion and validation but a form formatting interceptor places a formatted version of each form on top of the Value Stack, hiding the unformatted form.

These can be compared, along with manual validation. Existing code includes unannotated forms using formatted/unformatted field pairs, and view helpers reading formatted form field values.

Feature
Manual
String fields
Custom data tags
Replacement params
Custom tag uses converter
Formatted on Value Stack
Won't break existing code 1
Avoids formatted/unformatted field pairs
Allows manual conversion and validation
Standard/custom form field annotations C S C C C
Compatible with ModelDriven
Can write to action errors
Avoids custom annotation reading interceptor
Avoids replacement parameter interceptor
Avoids custom tags
Automated form formatting 2 3 3 3

1 Automated form formatting cannot be used.
2 Manual call to formatForms().
3 Some data types, particularly dates, will need tag parameters.

Redesigning forms to not use formatted/unformatted field pairs and place formatted form fields on the Value Stack is clearly the best option but breaking existing code and incompatibility with manual validation is a deal breaker. This will be the subject of a future article.

Next part

Continued in Example.