Friday, November 13, 2009

Annotations and bean validation with Groovy

I was looking for something like annotations driven validation for Groovy. Something like JSR-175 but... without JSR-175. Maybe something like Spring Validator would be nice but... without Spring.
Something like this:


class FooBeanWithValidations {

@NotEmpty
String id

}

I have reviewed some options, but i was looking for somthing very simple and plain...so, finally, i have to write it by myself...
First I defined the annotation class:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NotEmpty {

}

And then i writed a Validation class which handles the annotations and performs validation logic:

class Validator {

/**
* Helper method for apply a closure over all annotated bean properties
*/
protected static def forEachAnnotatedField(def clazz, def annotationClass, def closure) {

if (clazz in [Object, GroovyObject]) {
return
}

def properties = clazz.declaredFields
def annotated = []
annotated.addAll(properties.findAll {field ->
def annot = field.annotations.find {annotation->
return (annotationClass.isAssignableFrom(annotation.class))
}

if (annot){
closure(field, annot, clazz)
}
})

forEachAnnotatedField(clazz.superclass, annotationClass, closure)
}


/**
* Perform NonEmpty validations
*/
static def validateNotEmpty(def bean) {

forEachAnnotatedField (bean.class, NotEmpty.class) {field, annotation, clazz ->
def value = bean."${field.name}"

//Be aware with boolean values. False value are not empties!!
if (value instanceof Boolean) {
return
}

if (!value){
throw new ValidationException(bean, field.name, null)
}
}
}

static def validate(def bean) {

//Call other validation methods
validateNotEmpty(bean)
}

}

And voila... you can call validate method over any bean using Groovy Categories:

def bean = new FooBeanWithValidations()
use(Validator) {
bean.validate()
}

Or you can inject a validation method int bean's MetaClass

FooBeanWithValidations.metaClass.validate = {Validator.validate(this)}

No comments:

Post a Comment