Using JaValid with Spring to Validate Beans during Post Processing

JaValid is an annotation-based framework for validating fields or methods (i.e. NotNull, NotEmpty, etc.). We initially leveraged it in CAS to provide domain-validation to credential objects. This would allow the domain class to contain all the information about itself (similar to what Grails does).
CAS previously used some custom code in the Inspektr library to validate Spring beans via a BeanPostProcessor. Some of the code in Inspektr and JaValid was similar (i.e. the annotations) such that we figured it might be better to leverage more of JaValid (less code for us to maintain). To that end, we’ve managed to construct a BeanPostProcessor that leverages JaValid for validating the properties of Spring beans after they are created. I’ve pasted it below for anyone who’s interested in doing something similar:

/**
 * Copyright 2008 JA-SIG, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jasig.cas.server.util;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.binding.message.MessageResolver;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.javalid.core.AnnotationValidator;
import org.javalid.core.AnnotationValidatorImpl;
import org.javalid.core.ValidationMessage;

import java.util.List;
import java.util.Locale;

/**
 * Implementation of a {@link org.springframework.beans.factory.config.BeanPostProcessor} that uses Javalid to validate
 * properties of POJOs managed by Spring.
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 4.0.0
 */
public final class JavalidAnnotationValidatorBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    private final AnnotationValidatorImpl annotationValidator;

    private String pathPrefix = "";

    private String group = null;

    private int recursiveLevels = 2;

    private final ResourceBundleMessageSource resourceBundleMessageSource;

    public JavalidAnnotationValidatorBeanPostProcessor(final String configLocation) {
        if (configLocation != null) {
            this.annotationValidator = new AnnotationValidatorImpl(configLocation);
        } else {
            this.annotationValidator = new AnnotationValidatorImpl();
        }

        this.resourceBundleMessageSource = new ResourceBundleMessageSource();
        this.resourceBundleMessageSource.setBasename("org/javalid/core/validator/jv_messages");
    }

    public JavalidAnnotationValidatorBeanPostProcessor() {
        this(null);
    }

    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
        final List<ValidationMessage> messages = this.annotationValidator.validateObject(bean, this.group, this.pathPrefix, true, this.recursiveLevels);
        final StringBuilder builder = new StringBuilder();

        if (messages.isEmpty()) {
            return bean;
        }

        builder.append("bean '");
        builder.append(beanName);
        builder.append("' encountered errors on properties: '");
        for (final ValidationMessage message : messages) {
            builder.append("[property=");
            builder.append(message.getPath());
            builder.append(";error='");
            builder.append(this.resourceBundleMessageSource.getMessage(message.getMessage(), message.getValues(), Locale.getDefault()));
            builder.append("'] ");
        }

        throw new FatalBeanException(builder.toString());
    }
}

0 comments ↓

There are no comments yet...Kick things off by filling out the form below.

Leave a Comment

Spam protection by WP Captcha-Free