The Java Object Validation Framework
Download (SourceForge Hosted)
The Importance Of Being Valid
Validation of Java objects and their properties is not in the top ten list of important Java technologies. That's probably a good thing. Unfortunately, it also means that not a lot of attention is given to it. For the most part, validation is left up to presentation-layer frameworks. They're tied in very tightly and have little interest or usefulness outside of those frameworks. The only major exception to this is commons-validator, the validation framework that is part of Apache's Jakarta Commons project. And though it's certainly usable, it's far from a well-designed, flexible framework. There's also the small push to put validation in annotations, now that they are part of the language. Aspect-oriented programming also provides a method of injecting validation, though it's not technically a validation framework.
And then there's business rules engines. Many believe that using a rules engine for validation is not only feasible, but a good idea. These engines certainly have the power to validate data. However, using a rules engine to validate data is like using a sledge hammer to nail some tacks. Not only is it "too much," but it wasn't designed for it. Rules engines were designed to make decisions. Validation doesn't involve making decisions: it involves looking at data and ensuring that it's "valid." The "decision" in that case is "This data is valid. Have a nice day." There are no side effects.
What Constitutes a Good Validation Framework?
What makes a good validation framework is what you need it to do. It's not a glamorous technology that should solve world hunger. If using the framework involves significant amounts of time for the level of complexity you're using it for, then it's getting in the way. If you complain about a persistence framework getting in your way, then the last thing you need is a validation framework doing the same (meaning: that persistence framework is definitely in the top ten list of important Java technologies, but the validation framework isn't).
Having said that, however, it's important to have a framework that is powerful enough to handle some fairly complex validations. Otherwise, you end up working outside the framework, or you have to add to it or tweak it to get it to work. Your time is better spent elsewhere.
The following is a list of some features or capabilities of a good validation framework. In some cases, this is more than you need. In others, it may not be enough.
As mentioned earlier, keeping the API for a validation framework simple and minimal is usually appreciated by those that have to use it. By keeping code to the minimum, injecting validation into an application is much easier.
Of course, there are two side to this. If the opposite were true, and the amount of code was significant, then it imposes itself upon the application considerably. It's assumed that there's a trade-off between code and configuration. Either you have lots of one and not much of the other or the other way around. If that's not true, then you're paying for too much of one or the other. Given that, if you're going to end up with some configuration, anyway, then you might as well maximize it in order to minimize the amount of code. The secret is how extreme to either side you can get without giving up flexibility and the ability to integrate.
Since validation failures may need to be displayed in different localized languages, it's important that the framework support that capability. For Java, this usually means the support of pulling text from resource bundles.
It would be nice if all that configuration or code could be regurgitated into human-readable documentation. Similar to JavaDoc, providing the capability to transform validation information into documentation that can be read by developers, management, and even users is certainly a nice feature. This is more of a nice-to-have than a fundamental feature, but it's also one that doesn't exist (to my knowledge) for any particular framework out there.
All too often, simple Java validation frameworks, especially those that are tied to a presentation framework, either don't provide multi-field support, or they do, but it's tacked on as an afterthought. A good framework should support the ability to push multiple fields (in other words, a data set) into a single validator (assuming it supports it). It should be easy and intuitive and shouldn't feel tacked on.
For example, using annotations for validation may seem like a good idea...until you try to validate multiple fields. Since annotations are designed around single things (fields, methods, etc.), it's not a native concept to wrap multiple "things" around one annotation (though you could probably come up with a way to get around it, but ultimately, it'll feel "tacked on").
Presentation frameworks tend to have this same problem: validations are defined using some tag (or as an extension on an existing tag), and adding support for multiple fields becomes problematic (again, there's usually a way to get around the issue, but it almost always feels "tacked on").
One of the problems with putting everything in configuration is that there tends to become way too much configuration. If it's all in code, you have the same issue, only that it's with too much code. When it's in code, though, there are existing facilities that make it easy to re-use that code. This typically isn't the case for configuration. Therefore, a validation framework that relies upon configuration should provide an easy way to re-use existing configuration in order to minimize it.
This is a general capability that means the framework should be extensible, changeable, and easily configurable. There is no single feature that solves this and is more of a vague subjective measure of how easy a framework is to work with, especially when it doesn't do exactly what you need. This is true of any type of framework.
Dynamic Message Support
Ultimately, validation failures get reported to a user (or some where the user will ultimately look, such as a log file). Since individual validators can be used for different fields and for different reasons, it's important that the messages they ultimate generate are not so generic or specific that they can't be used elsewhere. In this case, it's better to allow the messages to be dynamically generated so that they can be configured for each individual use (if appropriate). Getting that to work without significant extra configuration is tricky. However, providing the solution definitely sets the framework apart from the others.
Another aspect of this issue is allowing individual validators to report multiple types of failure messages. For example, if you have a validator that checks the length of a string field, it may need to report a different message for when the length of the string is too long than for when it is too short. The different messages may be fundamentally different. It should not be assumed that a given individual validator will never report more than one type of failure (and, hence, a failure message).
Dependency support means providing support for validations being dependent upon other validations, or, more specifically, support for validations being dependent upon the outcome of other validations. For example, if one validator checks to ensure that a particular field is not null, a failure would mean that any other validations on that object should not proceed, since they'll all fail.
Since a decent validation framework shouldn't be tied to any given layer or other framework (such as a presentation framework), it's important that it support integration with existing frameworks. For example, it should support integration with inversion of control containers, presentation frameworks, etc. This typically would require framework-specific code, but the payoff is that it'll be usable within an application that is being built on top of those frameworks. Otherwise, having a great validation framework that can't work with your application does no one any good.