This blog entry is a general overview of the Bean Validation specification. Future blog entries will follow and will dive into specific aspects of the specification.
We have just released an early draft review of JSR 303 Bean Validation. The goal of this draft is to gather feedbacks and comments from the multi-facets community
- application developers (SE, EE, GUI, process, database)
- library developers
- tool developers
- other JSR expert groups including JSF 2.0, Java Persistence 2.0 and WebBeans
Please download the specification draft and give us feedback.
Goals
Validating data is a common task that is spread across several (if not all) layers of today's applications. Because each layer defines validation rules its own way, duplication and errors are quite common.
The Bean Validation specification addresses this problem by providing:
- an extensible annotation-based validation declaration model (XML deployment descriptors will be available as well)
- a standard runtime validation API
- a standard metadata query API
By providing a standard frame set around object validation, the specification aims at being the main provider for validation declaration and validation execution in the Java ecosystem. The same set of validations will be shared by all the application layers.
Expressing constraints
Constraints are primarily expressed through annotations. Adding a constraint on a class, field or getter is as simple as adding a constraint annotation on it. The annotated element value is checked by the constraint.
public class Address {
@NotEmpty @Max(50)
private String street1;
@Max(50)
private String street2;
@Max(9) @NotNull
private String zipcode;
...
}
Validating an object is equivalent to validate all the constraints declared on:
- its fields
- its getters
- its class
- its superclasses
- its interfaces
Mind your own constraint
Constraints are not limited to built-in annotations. Any application can define its own additional set of constraints. A constraint is comprised of:
- an annotation
- a constraint validation implementation
While the annotation expresses the constraint on the domain model, the validation implementation decides whether a given value passes the constraint or not.
message
A constraint can define a custom error message returned when failure occurs.
public class Address {
@NotEmpty(message="The street is mandatory")
private String street1;
The specification provides a way to externalize these messages: this will be covered in a later post.
object graph validation
It is handy to validate an object graph as a whole rather than validate every single object manually. @Valid allows you to include associated objects to the validation process
public class Order {
@OrderNumber private String orderNumber;
@Valid @NotNull private Address delivery;
}
When an order object is validated, its address is validated as well.
Validating constraints
A Validator validates objects (graphs) of a given type. When an object is validated, all declared constraints are validated (from fields, getters, the class itself and associated objects if marked as such). The validation will process all constraints and return the list of all failing ones. This is quite useful to display all erroneous fields in a user interface.
Validator<Address> addressValidator = ...;
for (InvalidConstraint<Address> error : addressValidator.validate(address) ) {
displayErrorByField(error.getPropertyPath(), error.getMessage());
}
The API also allows to validate a given property rather than the whole object graph for finer grained validation, possibly even before setting the value. This situation arises when an object is gradually populated and needs to be validated.
//apply the street1 constraints on the value
addressValidator.validateValue("street1", "3340 peachtree Rd NE");
It is also possible to validate a subset of the declared constraints rather than all available constaints (using the notion of constraint groups). This is useful in two scenarios:
- validate a gradually populated object graph (wizard style UI or use case driven validation)
- validate a set of constraints before an other set of constraints (the second relying on the first or being expensive resource-wise)
Groups will be covered in a future post.
Sharing constraint metadata
The Bean Validation API exposes all the constraint metadata for a given class:
- describes the constraints of a given element
- exposes the constraint properties
- etc
Metadata information is useful for tools (such as IDEs) and libraries interacting beyond the frontier of Java (database, javascript libraries and so on).
The grand scheme of things
The goal of JSR 303 is to be the main runtime checking solution and metadata repository for validation rule. This common language between application developers, libraries and JSRs in need for validation (runtime and metadata) will free Java developers from multiple constraint declarations and incompatible validation implementations.
We have specifically planned to work with expert groups from JSF 2.0, Java Persistence 2.0 and WebBeans to offer a smooth and homogeneous integration at the Java platform level. You can envision your constraints propagated to the database schema, to AJAX UI components and checked at various levels of the Java application (presentation, business, persistence layers), all from the same declaration source: your domain model.
This blog entry only brushes the main usages and APIs of the Bean Validation specification. I will follow with some posts covering in more depth:
- how to write your own constraints and why it matters
- groups: define subsets of constraints, why and how
- beyond the Java land: the metadata API
Please download the specification draft and give us feedback.
Nice, but isn't this just Hibernate Validator with different class and package names?
No it's not :)
Yes the spec has been inspired by Hibernate Validator, XWork, Riffle and other validation frameworks out there. Yes the ideas are converging, that's the whole point of a spec: standardized ideas accepted by a field.
There are the improvements I find most interesting compared to Hibernate Validator:
It makes a big difference.
I've read the specification and really like it. Groups and metadata are great adds.
However I haven't see a way to add a multiple field validation. E.g.:
public class Bean { private Date before; private Date afterBefore; ... }What I want is a way to validate fields before and afterBefore together. Of course I could write a object constraint. However I would like to write:
@MyCustomValidation public class Bean { @Before private Date before; @AfterBefore private Date afterBefore; ... } public class CustomConstraint implements Constraint<MyCustomValidation>, StandardConstraint { public boolean isValid(@Before Objet v1, @AfterBefore Object v2) { ... } public StandardConstraintDescriptor getStandardConstraints() { return new StandardConstraintDescriptor() { public Class<Annotation>[] getFields() { return Arrays.asList(Before.class, AfterBefore.class).toArray(); } }; }Could you understand?
Anyway, the specification is superb, a must have.
In page 12 you give best practices to write constraints. Is it possible to write the following and not violate the best practice?
public class AfterCurrentDate implements Constraint<After> { public boolean isValid(Date date) { return date == null || date.after(new Date()); }http://oval.sf.net/ is another great validation framework that supports both on-demand validation and AspectJ integration for aspect-based on-the-fly constraint validation which allows also validating method parameters. It would be really great if you had a look at this framework as well.
I have sent a couple of emails to the JSR comment list, but I have failed to see a list of existing emails. Is it really the case that the comments are not public? I would think it to be useful to make this process open, I am surprised that the JSR process works like this.
OVal is a very nice framework. But only part of it is the main purpose of JSR 303. Contract by design is subject of JSR 305. And the hocks to when the validation should be evaluated is external to the definition of the constraints, i.e., i hope that JEE 5.1 or 6, do this.
how would it work if you have more than one @Before / @AfterBefore in your class?
So far, I have not seen a solution that addresses most use cases aside from an object level validation.
If you refer to the null logic, yes your logic is correct. If the date is null, you return true.
If you refer to the typed parameter then no, you need to accept Object.
The reason behind this choice is that some validator accept multiple types. Object is the only common denominator. If you only accept a sub type (as your example shows), the bean validation implementation must deal with type inconsistency. This is fine in itself but it means type checking is split between the bean validation provider and the constraint implementation. This could lead to inconsistent behaviors.
So far the spec delegates type checking to the implementation.
Oval was very similar to Hibernate Validator last time I checked and has extensions to do programming by contract.
Programming by contract is beyond the scope of the 303 specification mandate, but we are seriously thinking providing extension points in the spec to allow application frameworks that can intercept operations (whether it be a full fledge AOP solution or an interceptor based solution) to plug the JSR 303 core functionalities.
If you want this integrated in Java EE 6, you better start emailing and lobbying the expert group soon :)
I agree with you Stephane, the email solution is not very practical. Let me think about it and find a solution.
If you find more then one annotation in the class, collect all fields and pass as a Array to the constraint. Let's try:
@MyCustomValidation public class Bean { @Before private Date before1; @Before private Date before2; @AfterBefore private Date afterBefore; ... } public class CustomConstraint implements Constraint<MyCustomValidation>, StandardConstraint { public boolean isValid(@Before Objet v1, @AfterBefore Object v2) { ... Date[] befores = (Date[]) v1; ... Date[] after = (Date) v2; ... } public StandardConstraintDescriptor getStandardConstraints() { return new StandardConstraintDescriptor() { public Class<Annotation>[] getFields() { return Arrays.asList(Before.class, AfterBefore.class).toArray(); } }; } }Possible?
But it still delegates. Just add a open type generic to the interface:
public interface Constraint<A extends Annotation, T> { void initialize(A constraintAnnotation); boolean isValid(T... values); } public class AfterCurrentDate implements Constraint<After, Date> { public boolean isValid(Date date) { return date == null || date.after(new Date()); } }IMHO programming by contract is subject of JSR 305.
Keep us posted :D
The forum has been opened. No more excuse.
Not sure I quite follow your reasoning. Let's follow up on the forum
What I am missing is the possibility to validate an object differently, depending on the current . I.e, an account object must be validate differently, if I want to create a new account, or if I want to change that account. So I am not talking about simple syntactic validations but validations depending on the state of the object or some other circumstance.