All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.droitateddb.builder.schema.reader.ColumnValidationReader Maven / Gradle / Ivy

package org.droitateddb.builder.schema.reader;

import org.droitateddb.builder.schema.data.ColumnValidation;
import org.droitateddb.builder.schema.data.ValidatorInfo;
import org.droitateddb.builder.schema.visitor.ColumnDeclaredTypeRetrievalVisitor;
import org.droitateddb.builder.schema.visitor.DefaultTypeVisitor;
import org.droitateddb.builder.schema.visitor.ValidatorAllowedTypeRetrievalVisitor;
import org.droitateddb.validation.Validator;

import javax.annotation.processing.Messager;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Falk Appel
 * @author Alexander Frank
 */
public class ColumnValidationReader implements Reader {

    public static final String VALIDATOR_VALUE_METHOD_NAME = "value";

    private VariableElement column;
    private Elements elements;
    private final Messager messager;

    public ColumnValidationReader(final VariableElement column, final Elements elements, final Messager messager) {
        this.column = column;
        this.elements = elements;
        this.messager = messager;
    }

    @Override
    public ColumnValidation read() {
        ColumnValidation columnValidation = new ColumnValidation();

        List annotationMirrors = column.getAnnotationMirrors();
        for (AnnotationMirror variableAnnotationMirror : annotationMirrors) {
            Element element = variableAnnotationMirror.getAnnotationType().asElement();
            for (AnnotationMirror annotationTypeMirror : element.getAnnotationMirrors()) {
                if (isValidatorAnnotation(annotationTypeMirror)) {
                    String validatorClass = getValidatorClass(annotationTypeMirror, element);
                    String validatorAnnotation = element.toString();
                    Map parameter = getValidationParameter(variableAnnotationMirror);
                    if (isParameterTypesValid(parameter)) {
                        columnValidation.add(new ValidatorInfo(validatorClass, validatorAnnotation, parameter));
                    } else {
                        messager.printMessage(Diagnostic.Kind.ERROR, "Validator annotation " + validatorAnnotation + " has invalid parameters types. Allowed are numbers (primitive and boxed) and String", element);
                    }
                }
            }
        }

        return columnValidation;
    }

    private boolean isParameterTypesValid(Map parameter) {
        for (Object paramValue : parameter.values()) {
            if (!isValid(paramValue)) {
                return false;
            }
        }
        return true;
    }

    private boolean isValid(Object value) {
        Class paramType = value.getClass();
        return paramType.equals(java.lang.String.class)  //
                || paramType.equals(java.lang.Integer.class) //
                || paramType.equals(java.lang.Float.class) //
                || paramType.equals(java.lang.Double.class) //
                || paramType.equals(java.lang.Long.class) //
                || paramType.equals(java.lang.Short.class) //
                || paramType.equals(java.lang.Byte.class);
    }

    private boolean isValidatorAnnotation(AnnotationMirror mirror) {
        return mirror.getAnnotationType().asElement().toString().equals(Validator.class.getCanonicalName());
    }

    private String getValidatorClass(AnnotationMirror mirror, Element element) {
        Map elementValues = mirror.getElementValues();
        for (Map.Entry entry : elementValues.entrySet()) {
            if (entry.getKey().getSimpleName().toString().equals(VALIDATOR_VALUE_METHOD_NAME)) {
                AnnotationValue value = entry.getValue();
                TypeElement acceptedType = value.accept(new ValidatorAllowedTypeRetrievalVisitor(column, messager), null);
                TypeElement actualType = column.accept(new ColumnDeclaredTypeRetrievalVisitor(), null);
                TypeKind columnTypeKind = column.asType().getKind();

                if (columnTypeKind.isPrimitive() && compareTypeWithPrimitive(acceptedType, columnTypeKind)) {
                    return value.getValue().toString();
                } else if (!columnTypeKind.isPrimitive() && compareTypeWithDeclared(acceptedType, actualType)) {
                    return value.getValue().toString();
                } else {
                    messager.printMessage(Diagnostic.Kind.ERROR, "The validator annotation " + element.toString() + " is not allowed on this type of column. Accepted is " + acceptedType.toString(), column);
                    return null;

                }
            }
        }
        messager.printMessage(Diagnostic.Kind.ERROR, "No value set for Validator annotation", mirror.getAnnotationType().asElement());
        return null;
    }

    private boolean compareTypeWithPrimitive(TypeElement acceptedType, TypeKind columnTypeKind) {
        return acceptedType.getQualifiedName().toString().equals(getBoxedClassName(columnTypeKind)) || acceptedType.getQualifiedName().toString().equals(Number.class.getCanonicalName());
    }

    private boolean compareTypeWithDeclared(TypeElement acceptedType, TypeElement actualType) {
        if (acceptedType.getQualifiedName().equals(actualType.getQualifiedName())) {
            return true;
        }

        TypeMirror superclass = actualType.getSuperclass();
        if (superclass.getKind().equals(TypeKind.NONE)) {
            return false;
        } else {
            TypeElement superTypeElement = superclass.accept(new DefaultTypeVisitor() {
                @Override
                public TypeElement visitDeclared(DeclaredType t, Void aVoid) {
                    return (TypeElement) t.asElement();
                }
            }, null);
            return compareTypeWithDeclared(acceptedType, superTypeElement);
        }
    }

    private String getBoxedClassName(TypeKind kind) {
        switch (kind) {
            case LONG:
                return Long.class.getCanonicalName();
            case INT:
                return Integer.class.getCanonicalName();
            case BYTE:
                return Byte.class.getCanonicalName();
            case SHORT:
                return Short.class.getCanonicalName();
            case FLOAT:
                return Float.class.getCanonicalName();
            case DOUBLE:
                return Double.class.getCanonicalName();
            default:
                return "Unknown";
        }
    }

    private Map getValidationParameter(AnnotationMirror mirror) {
        Map elementValues = elements.getElementValuesWithDefaults(mirror);
        Map parameter = new HashMap();
        for (Map.Entry elem : elementValues.entrySet()) {
            parameter.put(elem.getKey().getSimpleName().toString(), elem.getValue().getValue());
        }
        return parameter;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy