luanpotter/validum

View on GitHub
src/main/java/xyz/luan/validum/validations/Array.java

Summary

Maintainability
A
1 hr
Test Coverage
package xyz.luan.validum.validations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import xyz.luan.validum.Validation;
import xyz.luan.validum.Validation.DefaultTypes;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@Validation(defaultType = { DefaultTypes.ARRAY }, value = { Map.class })
public @interface Array {

    int minLength() default -1;

    int maxLength() default -1;

    public static class Validator implements xyz.luan.validum.AnnotationValidator<Object, Array> {

        @Override
        public List<String> validate(Object array, Array annotation) {
            if (array == null) {
                return Collections.emptyList();
            }

            int size = getArrayLength(array);
            List<String> errors = new ArrayList<>();

            if (annotation.minLength() != -1 && size < annotation.minLength()) {
                errors.add("Array.lengthBelow{" + annotation.minLength() + "}");
            }

            if (annotation.maxLength() != -1 && size > annotation.maxLength()) {
                errors.add("Array.lengthAbove{" + annotation.maxLength() + "}");
            }

            return errors;
        }

        public static int getArrayLength(Object array) {
            if (array.getClass().isArray()) {
                return java.lang.reflect.Array.getLength(array);
            }

            if (array instanceof Collection) {
                return Collection.class.cast(array).size();
            }

            if (array instanceof Map) {
                return Map.class.cast(array).size();
            }

            if (array instanceof Iterable) {
                return getLengthForIterable(array);
            }

            throw new AssertionError("Unexpected array type for @Array. Must be either primitive array or a Collection.");
        }

        private static int getLengthForIterable(Object array) {
            Iterator<?> it = Iterable.class.cast(array).iterator();
            int i;
            for (i = 0; it.hasNext(); i++, it.next()) {
            }
            return i;
        }
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.FIELD, ElementType.TYPE_USE })
    @Validation(defaultType = { DefaultTypes.ARRAY })
    public @interface Fixed {
        int value();

        public static class Validator implements xyz.luan.validum.AnnotationValidator<Object, Fixed> {

            @Override
            public List<String> validate(Object array, Fixed annotation) {
                if (array == null) {
                    return Collections.emptyList();
                }
                int size = xyz.luan.validum.validations.Array.Validator.getArrayLength(array);
                List<String> errors = new ArrayList<>();

                if (size != annotation.value()) {
                    errors.add("Array.lengthDiffers{" + annotation.value() + "}");
                }

                return errors;
            }
        }
    }
}