Package org.gwtoolbox.bean.rebind.validation

Source Code of org.gwtoolbox.bean.rebind.validation.ConstraintDefinition

package org.gwtoolbox.bean.rebind.validation;

import com.google.gwt.core.ext.typeinfo.JType;
import org.gwtoolbox.commons.collections.client.attributes.Attributes;
import org.gwtoolbox.commons.generator.rebind.AnnotationWrapper;
import org.gwtoolbox.commons.generator.rebind.GeneratorUtils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import javax.validation.groups.Default;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
* @author Uri Boness
*/
public class ConstraintDefinition {

    private Message message;

    private Class<? extends ConstraintValidator<?, ?>> validatorClass;

    private Attributes attributes;

    private Set<Class> groups;

    private Set<Class<? extends Payload>> payload;

    public ConstraintDefinition(Annotation annotation, JType type) {
        Class propertyClass = GeneratorUtils.loadClass(type);
        Class<? extends Annotation> annotationType = annotation.annotationType();
        AnnotationWrapper wrapper = new AnnotationWrapper(annotation);
        attributes = new AnnotationAttributes(annotation);

        groups = createClassSet((Class[]) wrapper.getValue("groups"));
        if (groups.isEmpty()) {
            groups.add(Default.class);
        }
        groups = GroupUtils.expandGroups(groups);

        payload = createClassSet((Class[]) wrapper.getValue("payload"));

        message = new Message(wrapper.getString("message"));

        // resolving the validator class
        Constraint  constraint = annotationType.getAnnotation(Constraint.class);
        Class<? extends ConstraintValidator<?, ?>>[] validatorClasses = constraint.validatedBy();
        if (validatorClasses.length == 0) {
            validatorClass = DefaultValidators.getValidatorClass(annotation, type);
        } else {
            for (Class<? extends ConstraintValidator<?, ?>> validatorClass : validatorClasses) {
                if (constraintValidatorSupportsType(validatorClass, propertyClass)) {
                    this.validatorClass = validatorClass;
                    break;
                }
            }
        }

        if (validatorClass == null) {
            throw new RuntimeException("Could not resolve appropriate constraint validator for annotation '" +
                    annotation.annotationType().getName() + "' on date type '" + type.getQualifiedSourceName() + "'");
        }
    }

    public Message getMessage() {
        return message;
    }

    public Class<? extends ConstraintValidator> getValidatorClass() {
        return validatorClass;
    }

    public Attributes getAttributes() {
        return attributes;
    }

    public Set<Class> getGroups() {
        return groups;
    }

    public Set<Class<? extends Payload>> getPayload() {
        return payload;
    }


    //================================================ Helper Methods ==================================================

    private <T> Set<Class<T>> createClassSet(Class<T>[] classes) {
        return new HashSet<Class<T>>(Arrays.asList(classes));
    }

    /**
     * According to JSR-303, each constraint annotation can define several constraint validator classes that can beconfigred
     * and validate the data. The main difference between these classes is that they must support different data types
     * which they can validate. The data type is determined by the generic parameter declaired by the class, which also
     * determines the first parameter that is passed in to the {@link ConstraintValidator#isValid(Object, ConstraintValidatorContext)}
     * method. This first parameter is therefore used to determine what validator class should be used for the given
     * property type.
     *
     * @param validatorClass The validator class.
     * @param propertyClass The property class.
     * @return
     */
    private boolean constraintValidatorSupportsType(Class<? extends ConstraintValidator<?, ?>> validatorClass, Class propertyClass) {
        for (Method method : validatorClass.getMethods()) {
            if ("isValid".equals(method.getName()) && method.getParameterTypes().length == 2 &&
                    method.getParameterTypes()[1] == ConstraintValidatorContext.class && method.getReturnType() == boolean.class) {

                // then it's probably the constraint isValid method, so we need to check the type of the first
                // parameter of this method. This type indicates what data type the constraint supports.

                Class paramType = method.getParameterTypes()[0];
                return paramType.isAssignableFrom(propertyClass);
            }
        }
        return false;
    }


}
TOP

Related Classes of org.gwtoolbox.bean.rebind.validation.ConstraintDefinition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.