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

org.minijax.validation.metadata.MinijaxConstraintDescriptor Maven / Gradle / Ivy

The newest version!
package org.minijax.validation.metadata;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jakarta.validation.Constraint;
import jakarta.validation.ConstraintTarget;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.Payload;
import jakarta.validation.ValidationException;
import jakarta.validation.constraints.AssertFalse;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.validation.metadata.ConstraintDescriptor;
import jakarta.validation.metadata.ValidateUnwrappedValue;

import org.minijax.validation.builtin.AssertFalseValidator;
import org.minijax.validation.builtin.AssertTrueValidator;
import org.minijax.validation.builtin.MaxValidator;
import org.minijax.validation.builtin.MinValidator;
import org.minijax.validation.builtin.NotBlankValidator;
import org.minijax.validation.builtin.NotEmptyValidators.NotEmptyValidatorForArray;
import org.minijax.validation.builtin.NotEmptyValidators.NotEmptyValidatorForCharSequence;
import org.minijax.validation.builtin.NotEmptyValidators.NotEmptyValidatorForCollection;
import org.minijax.validation.builtin.NotEmptyValidators.NotEmptyValidatorForMap;
import org.minijax.validation.builtin.NotNullValidator;
import org.minijax.validation.builtin.PatternValidator;
import org.minijax.validation.builtin.SizeValidators.SizeValidatorForArray;
import org.minijax.validation.builtin.SizeValidators.SizeValidatorForCharSequence;
import org.minijax.validation.builtin.SizeValidators.SizeValidatorForCollection;
import org.minijax.validation.builtin.SizeValidators.SizeValidatorForMap;

public class MinijaxConstraintDescriptor implements ConstraintDescriptor {
    private final T annotation;
    private final ConstraintValidator validator;
    private final String messageTemplate;

    private MinijaxConstraintDescriptor(final T annotation, final ConstraintValidator validator) {
        this.annotation = annotation;
        this.validator = validator;
        messageTemplate = getMessageTemplate(annotation);
    }

    @SuppressWarnings("rawtypes")
    public ConstraintValidator getValidator() {
        validator.initialize(annotation);
        return validator;
    }

    @Override
    public T getAnnotation() {
        return annotation;
    }

    @Override
    public List>> getConstraintValidatorClasses() {
        throw new UnsupportedOperationException();
    }

    @Override
    public String getMessageTemplate() {
        return messageTemplate;
    }

    @Override
    public Set> getGroups() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set> getPayload() {
        throw new UnsupportedOperationException();
    }

    @Override
    public ConstraintTarget getValidationAppliesTo() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Map getAttributes() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set> getComposingConstraints() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isReportAsSingleViolation() {
        throw new UnsupportedOperationException();
    }

    @Override
    public ValidateUnwrappedValue getValueUnwrapping() {
        throw new UnsupportedOperationException();
    }

    @Override
    public  U unwrap(final Class type) {
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    public static  MinijaxConstraintDescriptor build(final AnnotatedType annotatedType, final T annotation) {
        final Constraint constraint = annotation.annotationType().getAnnotation(Constraint.class);
        if (constraint == null) {
            return null;
        }

        final Class valueClass = ReflectionUtils.getRawType(annotatedType);
        final Class annotationClass = annotation.annotationType();

        if (constraint.validatedBy().length > 0) {
            return buildDeclaredValidator(annotation, constraint.validatedBy()[0]);

        } else if (annotationClass == AssertFalse.class) {
            return (MinijaxConstraintDescriptor) buildAssertFalseValidator((AssertFalse) annotation, valueClass);

        } else if (annotationClass == AssertTrue.class) {
            return (MinijaxConstraintDescriptor) buildAssertTrueValidator((AssertTrue) annotation, valueClass);

        } else if (annotationClass == Max.class) {
            return (MinijaxConstraintDescriptor) buildMaxValidator((Max) annotation, valueClass);

        } else if (annotationClass == Min.class) {
            return (MinijaxConstraintDescriptor) buildMinValidator((Min) annotation, valueClass);

        } else if (annotationClass == NotBlank.class) {
            return (MinijaxConstraintDescriptor) buildNotBlankValidator((NotBlank) annotation, valueClass);

        } else if (annotationClass == NotEmpty.class) {
            return (MinijaxConstraintDescriptor) buildNotEmptyValidator((NotEmpty) annotation, valueClass);

        } else if (annotationClass == NotNull.class) {
            return (MinijaxConstraintDescriptor) buildNotNullValidator((NotNull) annotation);

        } else if (annotationClass == Pattern.class) {
            return (MinijaxConstraintDescriptor) buildPatternValidator((Pattern) annotation, valueClass);

        } else if (annotationClass == Size.class) {
            return (MinijaxConstraintDescriptor) buildSizeValidator((Size) annotation, valueClass);

        } else {
            throw new ValidationException("Unrecognized constraint annotation: " + annotation);
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static  MinijaxConstraintDescriptor buildDeclaredValidator(final T annotation, final Class validatedBy) {
        try {
            return new MinijaxConstraintDescriptor<>(annotation, ((Class>) validatedBy).getConstructor().newInstance());
        } catch (final ReflectiveOperationException ex) {
            throw new ValidationException(ex);
        }
    }

    private static MinijaxConstraintDescriptor buildAssertFalseValidator(final AssertFalse assertFalse, final Class valueClass) {
        if (valueClass == boolean.class || valueClass == Boolean.class) {
            return new MinijaxConstraintDescriptor<>(assertFalse, AssertFalseValidator.INSTANCE);
        }

        throw new ValidationException("Unsupported type for @AssertFalse annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildAssertTrueValidator(final AssertTrue assertTrue, final Class valueClass) {
        if (valueClass == boolean.class || valueClass == Boolean.class) {
            return new MinijaxConstraintDescriptor<>(assertTrue, AssertTrueValidator.INSTANCE);
        }

        throw new ValidationException("Unsupported type for @AssertTrue annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildMaxValidator(final Max max, final Class valueClass) {
        if ((valueClass.isPrimitive() && valueClass != boolean.class) || Number.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(max, new MaxValidator(max));
        }

        throw new ValidationException("Unsupported type for @Min annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildMinValidator(final Min min, final Class valueClass) {
        if ((valueClass.isPrimitive() && valueClass != boolean.class) || Number.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(min, new MinValidator(min));
        }

        throw new ValidationException("Unsupported type for @Min annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildNotBlankValidator(final NotBlank notBlank, final Class valueClass) {
        if (CharSequence.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(notBlank, NotBlankValidator.INSTANCE);
        }

        throw new ValidationException("Unsupported type for @NotBlank annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildNotEmptyValidator(final NotEmpty notEmpty, final Class valueClass) {
        if (valueClass.isArray()) {
            return new MinijaxConstraintDescriptor<>(notEmpty, NotEmptyValidatorForArray.INSTANCE);
        }

        if (CharSequence.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(notEmpty, NotEmptyValidatorForCharSequence.INSTANCE);
        }

        if (Collection.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(notEmpty, NotEmptyValidatorForCollection.INSTANCE);
        }

        if (Map.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(notEmpty, NotEmptyValidatorForMap.INSTANCE);
        }

        throw new ValidationException("Unsupported type for @NotEmpty annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildNotNullValidator(final NotNull notNull) {
        return new MinijaxConstraintDescriptor<>(notNull, NotNullValidator.INSTANCE);
    }

    private static MinijaxConstraintDescriptor buildPatternValidator(final Pattern pattern, final Class valueClass) {
        if (CharSequence.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(pattern, new PatternValidator(pattern));
        }

        throw new ValidationException("Unsupported type for @Pattern annotation: " + valueClass);
    }

    private static MinijaxConstraintDescriptor buildSizeValidator(final Size size, final Class valueClass) {
        if (valueClass.isArray()) {
            return new MinijaxConstraintDescriptor<>(size, new SizeValidatorForArray(size));
        }

        if (CharSequence.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(size, new SizeValidatorForCharSequence(size));
        }

        if (Collection.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(size, new SizeValidatorForCollection(size));
        }

        if (Map.class.isAssignableFrom(valueClass)) {
            return new MinijaxConstraintDescriptor<>(size, new SizeValidatorForMap(size));
        }

        throw new ValidationException("Unsupported type for @Size annotation: " + valueClass);
    }

    private static String getMessageTemplate(final Annotation annotation) {
        try {
            return (String) annotation.annotationType().getMethod("message").invoke(annotation);
        } catch (final ReflectiveOperationException ex) {
            return null;
        }
    }
}