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

io.convergence_platform.common.validations.ValidationHelper Maven / Gradle / Ivy

Go to download

Holds the common functionality needed by all Convergence Platform-based services written in Java.

The newest version!
package io.convergence_platform.common.validations;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.convergence_platform.common.dto.RequestValidationFailureDTO;
import io.convergence_platform.common.dto.RequestValidationFieldFailureDTO;
import io.convergence_platform.common.exceptions.ManagedApiException;
import io.convergence_platform.common.responses.Errors;
import jakarta.validation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

public class ValidationHelper {
    private static List LIST_OF_ANNOTATIONS = List.of(
            AlphabeticalCharactersOnly.class,
            AlphaNumericalCharactersOnly.class,
            MaximumLength.class,
            MaximumValue.class,
            MinimumLength.class,
            MinimumValue.class,
            OneOf.class,
            Required.class,
            StringContains.class,
            StringNotContains.class,
            StringStartsWith.class,
            StringNotStartsWith.class,
            StringEndsWith.class,
            StringNotEndsWith.class,
            ValidateBase64.class,
            ValidateURL.class,
            ValidateYaml.class,
            ValidateUUID.class,
            ValidateJwt.class,
            ValidateEmail.class
    );

    public static void raiseValidationErrorForPathVariable(boolean valid, String validationName, String varName) {
        if (!valid) {
            RequestValidationFailureDTO details = new RequestValidationFailureDTO();
            RequestValidationFieldFailureDTO invalidPathVariable = new RequestValidationFieldFailureDTO();
            invalidPathVariable.field = varName;
            invalidPathVariable.location = "url";
            invalidPathVariable.messages.add("Failing to pass validation: '" + validationName + "'");
            details.errors.add(invalidPathVariable);

            throw new ManagedApiException(400,
                    Errors.INVALID_DATA,
                    "The request input is invalid, refer to body for details.",
                    details);
        }
    }

    public static boolean isValidDouble(String value) {
        try {
            Double.parseDouble(value);
            return true;
        } catch (Exception ex) {
        }
        return false;
    }

    public static void validateRequest(Object request) {
        if (request == null) {
            throw new ManagedApiException(400, Errors.INVALID_DATA, "The request input is null.");
        }

        validateObject(request, new ArrayList<>());
    }

    private static void validateObject(Object request, List parent) {
        Class cls = request.getClass();
        Field[] fields = cls.getDeclaredFields();
        RequestValidationFailureDTO details = new RequestValidationFailureDTO();

        for (Field field : fields) {
            List validationAnnotations = getValidationAnnotationsOnField(field);
            if (!validationAnnotations.isEmpty()) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(request);
                    for (Annotation validation : validationAnnotations) {
                        validateField(value, validation, parent, field, details);
                    }

                    if (value instanceof List) {
                        String fieldName = getFieldName(field);
                        List list = (List) value;
                        parent.add("");
                        for (int i = 0; i < list.size(); i++) {
                            parent.set(parent.size() - 1, fieldName + "[" + i + "]");
                            validateObject(list.get(i), parent);
                        }
                        parent.remove(parent.size() - 1);
                    } else if (value != null && value.getClass().isArray()) {
                        String fieldName = getFieldName(field);
                        parent.add("");
                        for (int i = 0; i < Array.getLength(value); i++) {
                            parent.set(parent.size() - 1, fieldName + "[" + i + "]");
                            validateObject(Array.get(value, i), parent);
                        }
                        parent.remove(parent.size() - 1);
                    } else if (value != null && isClassStructure(value)) {
                        String fieldName = getFieldName(field);
                        parent.add(fieldName);
                        validateObject(value, parent);
                        parent.remove(parent.size() - 1);
                    }
                } catch (ManagedApiException e) {
                    throw e;
                } catch (Exception e) {
                    throw new ManagedApiException(500, Errors.API_INTERNAL_ERROR, "An error occurred while validating the request body.");
                }
            }
        }

        if (!details.errors.isEmpty()) {
            throw new ManagedApiException(400,
                    Errors.INVALID_DATA,
                    "The request input is invalid, refer to body for details.",
                    details);
        }
    }

    private static boolean isClassStructure(Object value) {
        boolean primitive = value.getClass().isPrimitive();
        boolean isEnum = value.getClass().isEnum();
        return !primitive && !isEnum;
    }

    private static void validateField(Object value, Annotation validation, List parent, Field field, RequestValidationFailureDTO details) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Constraint constraint = validation.annotationType().getAnnotation(Constraint.class);
        Class validatorClass = constraint.validatedBy()[0];
        ConstraintValidator validator = (ConstraintValidator) validatorClass.newInstance();
        validator.initialize(validation);

        if (!validator.isValid(value, null)) {
            String fieldName = getFieldName(field);
            String message = (String) validation.annotationType().getMethod("message").invoke(validation);

            StringBuilder parentPath = new StringBuilder();
            for (String p : parent) {
                parentPath.append(p).append(".");
            }

            String fieldPath = parentPath + fieldName;
            RequestValidationFieldFailureDTO invalidPathVariable = getErrorEntry(details, fieldPath);
            invalidPathVariable.field = fieldPath;
            invalidPathVariable.location = "body";
            invalidPathVariable.messages.add(message);
        }
    }

    private static RequestValidationFieldFailureDTO getErrorEntry(RequestValidationFailureDTO details, String fieldPath) {
        RequestValidationFieldFailureDTO result = null;
        for (var e : details.errors) {
            if (e.field.equals(fieldPath)) {
                result = e;
                break;
            }
        }

        if (result == null) {
            result = new RequestValidationFieldFailureDTO();
            details.errors.add(result);
        }

        return result;
    }

    private static String getFieldName(Field field) {
        JsonProperty property = field.getAnnotation(JsonProperty.class);
        if (property != null) {
            return property.value();
        }
        return field.getName();
    }

    private static List getValidationAnnotationsOnField(Field field) {
        List result = new ArrayList<>();

        for (var annotation : field.getAnnotations()) {
            if (LIST_OF_ANNOTATIONS.contains(annotation.annotationType())) {
                result.add(annotation);
            }
        }

        return result;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy