Tuesday, January 26, 2010

I have made my own hands-on on this Bean Validation based on the [hibernate-validator-4.0.0.Beta2] and the experience was great. One thing that I have observed though is that there is no built-in annotation to check for a constraint spanning multiple properties, or to check if a certain property is valid based on other properties. One obvious example to this is validating date ranges where you would usually have two properties like startDate and endDate where it doesn't make sense to have a startDate property that is later than the endDate. You could say - why not create a new class-level constraint and
apply it like below:

Well, this is good because it is likely that I can reuse this constraint in other entities needing validation on date ranges (I just realized in writing this that it also interesting to post a blog on an implementation of the @ValidateDateRange annotation above). The following are some of the annotations which are reusable to other entities.

@NotNull

@NotEmpty

@Size

@Min

@Max

@DecimalMin

@DecimalMax

@Email

@Pattern

But how about other validation spanning multiple properties that is not likely to be reused in other entities (just like the sample class-level constraint @ValidPassengerCount in the Bean Validator documentation)? I believe, that to create two additional classes to support such simple validation requirement of an specific entity is too much work especially that it is most likely that in addition to checking if the number of passengers is valid , you will also have two or more other validation requirements on the same entity. For example, if I have three business logic for an entity to be validated, it means creating more or less six additional classes to support the three constraint validation. The sad thing is, I cannot reuse such custom constraint validations to other entities.

The Bean Validation reference implementation has @AssertTrue annotation which can be applied to a property or getter method, but an exception is raised if you will try to access other properties value inside a getter method.

So how then could we easily validate a business logic constraint that spans multiple properties without too much work? Our answer is the reusable @AssertMethodAsTrue class-level constraint annotation that accepts a method name as a parameter. The method name that you set as parameter should return a boolean value. An example would be:

Hi Dan,You cannot use the @AssertTrue on a validation that span multiple properties, like for example if you are checking if property1 is greater than property2 inside your method, then you will receive exception.