Add iterable objects validation (#970)

pull/979/head
John Niang 2020-07-14 00:15:16 +08:00 committed by GitHub
parent 83d4ca1565
commit 7a71c85862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 11 deletions

View File

@ -1,15 +1,14 @@
package run.halo.app.utils;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.FieldError;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Object validation utilities.
@ -30,7 +29,7 @@ public class ValidationUtils {
* @return validator
*/
@NonNull
public static Validator getValidatorOrCreate() {
public static Validator getValidator() {
if (VALIDATOR == null) {
synchronized (ValidationUtils.class) {
if (VALIDATOR == null) {
@ -52,17 +51,55 @@ public class ValidationUtils {
*/
public static void validate(Object obj, Class<?>... groups) {
Validator validator = getValidatorOrCreate();
Validator validator = getValidator();
// Validate the object
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(obj, groups);
if (obj instanceof Iterable) {
// validate for iterable
validate((Iterable<?>) obj, groups);
} else {
// validate the non-iterable object
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(obj, groups);
if (!CollectionUtils.isEmpty(constraintViolations)) {
// If contain some errors then throw constraint violation exception
throw new ConstraintViolationException(constraintViolations);
if (!CollectionUtils.isEmpty(constraintViolations)) {
// If contain some errors then throw constraint violation exception
throw new ConstraintViolationException(constraintViolations);
}
}
}
/**
* Validates iterable objects.
*
* @param objs iterable objects could be null
* @param groups validation groups
*/
public static void validate(@Nullable Iterable<?> objs, @Nullable Class<?>... groups) {
if (objs == null) {
return;
}
// get validator
Validator validator = getValidator();
// wrap index
AtomicInteger i = new AtomicInteger(0);
final Set<ConstraintViolation<?>> allViolations = new LinkedHashSet<>();
objs.forEach(obj -> {
int index = i.getAndIncrement();
Set<? extends ConstraintViolation<?>> violations = validator.validate(obj, groups);
violations.forEach(violation -> {
Path path = violation.getPropertyPath();
if (path instanceof PathImpl) {
PathImpl pathImpl = (PathImpl) path;
pathImpl.makeLeafNodeIterableAndSetIndex(index);
}
allViolations.add(violation);
});
});
if (!CollectionUtils.isEmpty(allViolations)) {
throw new ConstraintViolationException(allViolations);
}
}
/**
* mapkey:value = field:message

View File

@ -0,0 +1,84 @@
package run.halo.app.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.constraints.NotBlank;
import java.util.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Validation utils test.
*
* @author johnniang
*/
class ValidationUtilsTest {
Validator validator = ValidationUtils.getValidator();
@Test
void validateObjectTest() {
Car car = new Car(null);
Set<ConstraintViolation<Car>> violations = validator.validate(car);
validateObjectAssert(violations);
ConstraintViolationException exception = assertThrows(ConstraintViolationException.class,
() -> ValidationUtils.validate(car));
validateObjectAssert(exception.getConstraintViolations());
}
void validateObjectAssert(Set<? extends ConstraintViolation<?>> violations) {
assertEquals(1, violations.size());
ConstraintViolation<?> violation = violations.iterator().next();
assertEquals("name", violation.getPropertyPath().toString());
assertEquals("Name must not be blank", violation.getMessage());
}
@Test
void validateListTest() {
List<Car> cars = Arrays.asList(new Car(""),
new Car("car name"),
new Car(null));
ConstraintViolationException exception = assertThrows(ConstraintViolationException.class,
() -> ValidationUtils.validate(cars));
validateIteratorTest(exception.getConstraintViolations());
}
void validateIteratorTest(Set<? extends ConstraintViolation<?>> violations) {
assertEquals(2, violations.size());
LinkedList<? extends ConstraintViolation<?>> violationList = new LinkedList<>(violations);
violationList.sort(Comparator.comparing(v -> v.getPropertyPath().toString()));
// get first violation
ConstraintViolation<?> firstViolation = violationList.get(0);
// get second violation
ConstraintViolation<?> secondViolation = violationList.get(1);
assertEquals("name[0]", firstViolation.getPropertyPath().toString());
assertEquals("name[2]", secondViolation.getPropertyPath().toString());
}
/**
* Car entity.
*
* @author johnniang
*/
@Data
@AllArgsConstructor
static class Car {
@NotBlank(message = "Name must not be blank")
private String name;
}
}