mirror of https://github.com/halo-dev/halo
Add iterable objects validation (#970)
parent
83d4ca1565
commit
7a71c85862
|
@ -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,9 +51,13 @@ public class ValidationUtils {
|
|||
*/
|
||||
public static void validate(Object obj, Class<?>... groups) {
|
||||
|
||||
Validator validator = getValidatorOrCreate();
|
||||
Validator validator = getValidator();
|
||||
|
||||
// Validate the object
|
||||
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)) {
|
||||
|
@ -62,7 +65,41 @@ public class ValidationUtils {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字段验证错误转换为标准的map型,key:value = field:message
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue