Validator.java

package com.wilzwert.myjobs.core.domain.shared.validation;


import com.wilzwert.myjobs.core.domain.model.EntityId;

import java.net.MalformedURLException;
import java.net.URI;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.regex.Pattern;

/**
 * @author Wilhelm Zwertvaegher
 */

public class Validator {

    private final ValidationErrors validationErrors;

    public Validator() {
        validationErrors = new ValidationErrors();
    }

    public ValidationErrors getErrors() {
        return validationErrors;
    }

    private boolean notEmpty(String fieldName, Object fieldValue) {
        if(fieldValue == null
            || fieldValue instanceof String string && string.isEmpty()
            || fieldValue instanceof EntityId<?> entityId && entityId.value() == null) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_CANNOT_BE_EMPTY));
            return false;
        }
        return true;
    }

    public Validator requireNotNull(String fieldName, Object fieldValue) {
        if(null == fieldValue) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_CANNOT_BE_NULL));
        }
        return this;
    }

    public Validator requireNotEmpty(String fieldName, String fieldValue) {
        notEmpty(fieldName, fieldValue);
        return this;
    }

    public Validator requireNotEmpty(String fieldName, EntityId<?> id) {
        notEmpty(fieldName, id);
        return this;
    }

    public Validator requireValidEmail(String fieldName, String fieldValue) {
        String pattern = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
        if(notEmpty(fieldName, fieldValue) && !Pattern.compile(pattern).matcher(fieldValue).matches()) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.INVALID_EMAIL));
        }
        return this;
    }

    public Validator requireValidUrl(String fieldName, String fieldValue) {
        try {
            new URI(fieldValue).toURL();
            // we want at least something like domain.com
            // we have to check it because toURL accepts http://localhost or similar URLS
            if(!fieldValue.contains(".")) {
                throw new MalformedURLException();
            }

        } catch (Exception e) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.INVALID_URL));
        }
        return this;
    }

    public Validator requireMinLength(String fieldName, String fieldValue, int minLength) {
        if(minLength < 1) {
            throw new IllegalArgumentException("minLength must be greater than 0");
        }
        if(notEmpty(fieldName, fieldValue) && fieldValue.length() < minLength) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_TOO_SHORT));
        }
        return this;
    }

    public Validator requireMaxLength(String fieldName, String fieldValue, int maxLength) {
        if(maxLength < 1) {
            throw new IllegalArgumentException("maxLength must be greater than 0");
        }
        if(notEmpty(fieldName, fieldValue) && fieldValue.length() > maxLength) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_TOO_LONG));
        }
        return this;
    }

    public Validator requireMin(String fieldName, Integer fieldValue, int minValue) {
        if(notEmpty(fieldName, fieldValue) && fieldValue < minValue) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_VALUE_TOO_SMALL, Map.of("min", String.valueOf(minValue))));
        }
        return this;
    }

    public Validator requireMinIfNotNull(String fieldName, Integer fieldValue, int minValue) {
        if(fieldValue == null) {
            return this;
        }
        if(fieldValue < minValue) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_VALUE_TOO_SMALL, Map.of("min", String.valueOf(minValue))));
        }
        return this;
    }

    public Validator requireMax(String fieldName, Integer fieldValue, int maxValue) {
        if(notEmpty(fieldName, fieldValue) && fieldValue > maxValue) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_VALUE_TOO_BIG, Map.of("max", String.valueOf(maxValue))));
        }
        return this;
    }

    public Validator requireMaxIfNotNull(String fieldName, Integer fieldValue, int maxValue) {
        if(fieldValue == null) {
            return this;
        }
        if(fieldValue > maxValue) {
            validationErrors.add(new ValidationError(fieldName, ErrorCode.FIELD_VALUE_TOO_BIG, Map.of("max", String.valueOf(maxValue))));
        }
        return this;
    }

    public Validator require(String fieldName, BooleanSupplier supplier, ErrorCode errorCode) {
        if(!supplier.getAsBoolean()) {
            validationErrors.add(new ValidationError(fieldName, errorCode));
        }
        return this;
    }
}