Here are some questions about your approach:
In general, with the simplicity of baking your configuration data into
the Java source file, you lose the flexibility to make changes to the
configuration data without recompilation.
JavaServer Faces was targeted at the corporate developer. The very
concept of annotations and leveraging them for validation seems to go
beyond the realm of what the corporate developer can easily handle.
How slow is the reflection involved in the public static void validate()
method?
Is the complexity worth it?
In faces, currently a validator can be
1 a separate java class that implements the Validator interface. This
class is identified to the system by a combination of validatorId and
FQCN.
2 a method on a pojo that conforms to the signature of
Validator.validate(). The class on which this method is defined is
identified to the system by a combination of managed-bean-name and
FQCN.
In your system, you have the same amount of Java code to write, but
you can bake the validator itself into the bean that it is
validating. This is nice because logically it makes sense for the
validation logic to be tightly coupled to the bean...sometimes.
Note that you can achieve this same coupling using method 2 above.
public static class ReportName extends ValidatedString {
public ReportName(String string) throws ValidatedStringException {
super(string, StringTester.ANS, 20, 1);
}
}
...
private ReportName name;
The ReportName constructor specifies the allowed character set (ANS = alphanumeric + spaces) and min length / max length.
Then I register a custom converter to handle all ValidatedString types in faces-config:
<converter>
<converter-for-class>ValidatedString</converter-for-class>
<converter-class>ValidatedStringConverter</converter-class>
</converter>
The getAsObject() method of ValidatedStringConverter calls a method on ValidatedString to actually perform the validation.
This way, all validation logic is specified in the domain model, my view template requires no validation tags or rules, and all values on a form get validated, regardless of what kind of component they are bound to.
I've also written Hibernate custom type converters so I can use rich types in my domain model from end-to-end.
Now, I think annotations are a more compact way to express the validation rules than creating an inner class for each property as I've shown above. However, I don't know where I'd hook into JSF to actually run the validation, as the converter wiring depends on the model property extending some class.
Any ideas?
By the way, Ed, I'm a corporate developer, and I grok annotations no problem. In fact, I think it's easier than what I've already done with custom types. I love the richness and extensibility of JSF. I've been doing Web development for 11 years and JSF is the first framework I've seen that makes me feel like I don't need to learn another framework. You guys have absolutely nailed it.
Either way, I think the concerns about needing to modify validation rules at run time are quite valid. In my current project, this is necessary because many of our field defintions are dynamic based on run-time properties. At any rate, I think this indirection is easily done using either annotations or the custom converter approach. Instead of specifying the rule itself, the annotation or custom type would simply contain a key to a rules definition somewhere else.
Cheers!
/dmc