Listing 8: The final implementation of MethodInterceptor.
<Final MethodArgValidationInterceptor>
package jbriscoe.article.spring.validation.interceptor;
import java.beans.PropertyDescriptor;
import java.util.*;
import jbriscoe.article.spring.validation.exception.ValidationException;
import org.aopalliance.intercept.*;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.*;
public class MethodArgValidationInterceptor implements MethodInterceptor {
private List<Validator> validators = new ArrayList<Validator>();
private Log log = LogFactory.getLog(getClass());
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
final List<Errors> errors = new ArrayList<Errors>();
allMethodArgsLoop:
for (int i = 0; i < methodInvocation.getArguments().length; i++) {
final Object arg = methodInvocation.getArguments()[i];
// Inspect fields... of this arg.
inspectObject(errors, arg);
}
if (errors.size() > 0) {
log.warn("Validation error(s) found, throwing ValidationException.");
throw new ValidationException(errors);
}
return methodInvocation.proceed();
}
public List<Validator> getValidators() {
return validators;
}
public void setValidators(List<Validator> validators) {
this.validators = validators;
}
private void inspectObjectProperties(final Object arg,
final List<Errors> errors) throws Exception {
// Inspect supported properties.
final PropertyDescriptor[] propertyDescriptors = PropertyUtils
.getPropertyDescriptors(arg.getClass());
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final Object propertyValue = propertyDescriptor.getReadMethod().invoke(arg);
if (propertyValue != null
&& isArrayOrCollection(propertyValue.getClass())) {
if (propertyValue.getClass().isArray()) {
for (final Object propertyElementValue : ((Object[]) propertyValue)) {
for (final Validator validator : getValidators()) {
if (validator.supports(propertyElementValue.getClass())) {
log.debug("Validator supported: "
+ propertyElementValue.getClass());
validateAndAddErrors(propertyElementValue, validator, errors);
inspectObjectProperties(propertyElementValue, errors);
}
}
}
} else {
for (final Object propertyElementValue : ((Collection) propertyValue)) {
for (final Validator validator : getValidators()) {
if (validator.supports(propertyElementValue.getClass())) {
log.debug("Validator supported: " +
propertyElementValue.getClass());
validateAndAddErrors(propertyElementValue, validator, errors);
inspectObjectProperties(propertyElementValue, errors);
}
}
}
}
} else if (propertyValue != null) {
// Non-Scalar property
for (final Validator validator : getValidators()) {
if (validator.supports(propertyValue.getClass())) {
log.debug("Validator supported: " + propertyValue.getClass());
validateAndAddErrors(propertyValue, validator, errors);
inspectObjectProperties(propertyValue, errors);
}
}
}
}
}
private Errors validateAndAddErrors(final Object arg,
final Validator validator, final List<Errors> errors) {
final BindException objErrors = new BindException(arg, arg.getClass()
.getName());
validator.validate(arg, objErrors);
if (objErrors.hasErrors()) {
errors.add(objErrors);
}
return objErrors;
}
private void inspectObject(final List<Errors> errors, final Object arg)
throws Exception {
allValidatorLoop: for (final Validator validator : getValidators()) {
if (validator.supports(arg.getClass())) {
log.debug("Validator supported: " + arg.getClass());
validateAndAddErrors(arg, validator, errors);
inspectObjectProperties(arg, errors);
}
}
}
private boolean isArrayOrCollection(final Class clazz) {
return (clazz.isArray() || clazz.isAssignableFrom(List.class)
|| clazz.isAssignableFrom(ArrayList.class)
|| clazz.isAssignableFrom(Set.class)
|| clazz.isAssignableFrom(SortedSet.class)
|| clazz.isAssignableFrom(AbstractCollection.class)
|| clazz.isAssignableFrom(AbstractList.class)
|| clazz.isAssignableFrom(AbstractSet.class)
|| clazz.isAssignableFrom(HashSet.class)
|| clazz.isAssignableFrom(LinkedHashSet.class)
|| clazz.isAssignableFrom(LinkedList.class)
|| clazz.isAssignableFrom(TreeSet.class) || clazz
.isAssignableFrom(Vector.class));
}
}
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|