Package org.gwtoolbox.bean.rebind.validation

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

package org.gwtoolbox.bean.rebind.validation;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import org.gwtoolbox.bean.rebind.BeanOracle;
import org.gwtoolbox.bean.rebind.JProperty;
import org.gwtoolbox.commons.generator.rebind.AnnotationWrapper;
import org.gwtoolbox.commons.generator.rebind.GeneratorUtils;

import javax.validation.Constraint;
import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

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

    private BeanOracle beanOracle;

    private Map<String, List<ConstraintDefinition>> constraintsByProperty = new HashMap<String, List<ConstraintDefinition>>();
    private Set<String> constrainedProperties = new HashSet<String>();
    private Set<String> cascadeProperties = new HashSet<String>();

    private List<ConstraintDefinition> classLevelConstraints;

    public ValidationOracle(BeanOracle beanOracle) {
        this.beanOracle = beanOracle;
        classLevelConstraints = loadClassLevelConstraints(beanOracle);
        for (JProperty property : beanOracle.getProperties()) {
            List<ConstraintDefinition> constraints = loadConstraints(property);
            constraintsByProperty.put(property.getName(), constraints);
            if (!constraints.isEmpty()) {
                constrainedProperties.add(property.getName());
            }
            if (isCascade(property)) {
                cascadeProperties.add(property.getName());
            }
        }
    }

    public BeanOracle getBeanOracle() {
        return beanOracle;
    }

    public boolean hasClassLevelConstraints() {
        return classLevelConstraints != null && !classLevelConstraints.isEmpty();
    }

    public List<ConstraintDefinition> getClassLevelConstraints() {
        return classLevelConstraints;
    }

    public boolean hasValidatedProperties() {
        return !cascadeProperties.isEmpty() || !constrainedProperties.isEmpty();
    }

    public boolean isValidated(String propertyName) {
        return isCascade(propertyName) || !constraintsByProperty.get(propertyName).isEmpty();
    }

    public boolean isCascade(String propertyName) {
        return cascadeProperties.contains(propertyName);
    }

    public List<ConstraintDefinition> getConstraintDefinitions(String propertyName) {
        List<ConstraintDefinition> definitions = constraintsByProperty.get(propertyName);
        return definitions != null ? definitions : Collections.EMPTY_LIST;
    }


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

    private boolean isCascade(JProperty property) {
        JField field = property.getField();
        if (field != null && field.isAnnotationPresent(Valid.class)) {
            return true;
        }
        JMethod getter = property.getGetter();
        return getter != null && getter.isAnnotationPresent(Valid.class);
    }

    private List<ConstraintDefinition> loadClassLevelConstraints(BeanOracle beanOracle) {
        Class beanClass = GeneratorUtils.loadClass(beanOracle.getType());
        List<Annotation> constraintAnnotations = loadConstraintAnnotations(beanClass);
        if (constraintAnnotations == null || constraintAnnotations.isEmpty()) {
            return null;
        }
        classLevelConstraints = new ArrayList<ConstraintDefinition>(constraintAnnotations.size());
        for (Annotation annotation : constraintAnnotations) {
            classLevelConstraints.add(new ConstraintDefinition(annotation, beanOracle.getType()));
        }
        return classLevelConstraints;
    }

    private List<ConstraintDefinition> loadConstraints(JProperty property) {
        List<Annotation> constraintAnnotations = loadConstraintAnnotations(property);
        List<ConstraintDefinition> definitions = new ArrayList<ConstraintDefinition>(constraintAnnotations.size());
        for (Annotation annotation : constraintAnnotations) {
            definitions.add(new ConstraintDefinition(annotation, property.getType()));
        }
        return definitions;
    }

    private List<Annotation> loadConstraintAnnotations(JProperty property) {
        List<Annotation> annotations = new ArrayList<Annotation>();
        Field field = resolveField(property);
        if (field != null) {
            annotations.addAll(loadConstraintAnnotations(field));
        }
        Method getter = resolveGetterMethod(property);
        if (getter != null) {
            annotations.addAll(loadConstraintAnnotations(getter));
        }
        return annotations;
    }



    private List<Annotation> loadConstraintAnnotations(AnnotatedElement element) {
        List<Annotation> result = new ArrayList<Annotation>();
        for (Annotation annotation : element.getAnnotations()) {

            // the the annotation is marked with the @Constraint annotation we just add it
            if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
                result.add(annotation);
                continue;
            }

            // now we're looking for a list annotation. According to the specs the list annotation should only have
            // a value attribute of an array type where the components of the array are annotations marked with the @Constraint
            // annotation
            AnnotationWrapper wrapper = new AnnotationWrapper(annotation);
            if (!wrapper.getAttributeNames().contains("value")) {
                continue;
            }
            Object value = wrapper.getValue("value");
            if (!value.getClass().isArray()) {
                continue;
            }
            Class subAnnotationType = value.getClass().getComponentType();
            if (!subAnnotationType.isAnnotation()) {
                continue;
            }
            if (!subAnnotationType.isAnnotationPresent(Constraint.class)) {
                continue;
            }
            for (int i = 0; i < Array.getLength(value); i++) {
                annotation = (Annotation) Array.get(value, i);
                result.add(annotation);
            }
        }
        return result;
    }

    private Field resolveField(JProperty property) {
        if (property.getField() == null) {
            return null;
        }
        JClassType type  = property.getField().getEnclosingType();
        Class clazz = GeneratorUtils.loadClass(type);
        try {
            return clazz.getDeclaredField(property.getField().getName());
        } catch (NoSuchFieldException e) {
            return null;
        }
    }

    private Method resolveGetterMethod(JProperty property) {
        if (property.getGetter() == null) {
            return null;
        }
        return GeneratorUtils.resolveMethod(property.getGetter());
    }
}
TOP

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

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.