io.convergence_platform.common.validations.ValidationHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of service-lib Show documentation
Show all versions of service-lib Show documentation
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;
}
}