feat: 添加数组长度和集合大小的校验功能

- 在 ArrayPropertyValidator 中添加了 length 方法,用于校验数组长度。
- 在 CollectionPropertyValidator 中添加了 size 方法,用于校验集合大小。
This commit is contained in:
zhouxy108 2025-06-01 20:18:36 +08:00
parent 0a83116e81
commit 88b3226b17
4 changed files with 498 additions and 12 deletions

View File

@ -21,6 +21,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import xyz.zhouxy.plusone.commons.util.ArrayTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/**
* 针对数组类型的属性校验器
@ -81,8 +82,7 @@ public class ArrayPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> notEmpty(
Function<TElement[], E> e) {
withRule(ArrayTools::isNotEmpty, e);
return this;
return withRule(ArrayTools::isNotEmpty, e);
}
// ================================
@ -131,8 +131,7 @@ public class ArrayPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> isEmpty(
Function<TElement[], E> e) {
withRule(ArrayTools::isEmpty, e);
return this;
return withRule(ArrayTools::isEmpty, e);
}
// ================================
@ -185,20 +184,114 @@ public class ArrayPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Function<TElement, E> e) {
withRule(c -> {
return withRule(c -> {
for (TElement element : c) {
if (!condition.test(element)) {
throw e.apply(element);
}
}
});
return this;
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - length
// ================================
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param length 指定长度
* @param errMsg 异常信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> length(int length, String errMsg) {
return length(length, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param <E> 异常类型
* @param length 指定长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int length, Supplier<E> e) {
return length(length, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param <E> 异常类型
* @param length 指定长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int length, Function<TElement[], E> e) {
AssertTools.checkArgument(length >= 0,
"The expected length must be greater than or equal to 0.");
return withRule(s -> s == null || s.length == length, e);
}
static <TElement> boolean checkLength(TElement[] str, int min, int max) {
if (str == null) {
return true;
}
final int len = str.length;
return len >= min && len <= max;
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param errMsg 错误信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> length(int min, int max, String errMsg) {
return length(min, max, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int min, int max, Supplier<E> e) {
return length(min, max, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int min, int max, Function<TElement[], E> e) {
AssertTools.checkArgument(min >= 0, "min must be non-negative.");
AssertTools.checkArgument(min <= max, "min must be less than or equal to max.");
return withRule(s -> checkLength(s, min, max), e);
}
// ================================
// #endregion - length
// ================================
@Override
protected ArrayPropertyValidator<T, TElement> thisObject() {
return this;

View File

@ -22,6 +22,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/**
* 针对集合类型的属性校验器
@ -82,8 +83,7 @@ public class CollectionPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> notEmpty(
Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isNotEmpty, e);
return this;
return withRule(CollectionTools::isNotEmpty, e);
}
// ================================
@ -132,8 +132,7 @@ public class CollectionPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> isEmpty(
Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isEmpty, e);
return this;
return withRule(CollectionTools::isEmpty, e);
}
// ================================
@ -186,18 +185,112 @@ public class CollectionPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Function<TElement, E> e) {
withRule(c -> c.forEach(element -> {
return withRule(c -> c.forEach(element -> {
if (!condition.test(element)) {
throw e.apply(element);
}
}));
return this;
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - size
// ================================
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param size 指定大小
* @param errMsg 异常信息
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> size(int size, String errMsg) {
return size(size, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param <E> 异常类型
* @param size 指定大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int size, Supplier<E> e) {
return size(size, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param <E> 异常类型
* @param size 指定大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int size, Function<Collection<TElement>, E> e) {
AssertTools.checkArgument(size >= 0,
"The expected size must be greater than or equal to 0.");
return withRule(s -> s == null || s.size() == size, e);
}
static <TElement> boolean checkSize(Collection<TElement> str, int min, int max) {
if (str == null) {
return true;
}
final int size = str.size();
return size >= min && size <= max;
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param errMsg 错误信息
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> size(int min, int max, String errMsg) {
return size(min, max, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int min, int max, Supplier<E> e) {
return size(min, max, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int min, int max, Function<Collection<TElement>, E> e) {
AssertTools.checkArgument(min >= 0, "min must be non-negative.");
AssertTools.checkArgument(min <= max, "min must be less than or equal to max.");
return withRule(s -> checkSize(s, min, max), e);
}
// ================================
// #endregion - size
// ================================
@Override
protected CollectionPropertyValidator<T, TElement> thisObject() {
return this;

View File

@ -22,6 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import xyz.zhouxy.plusone.ExampleException;
import xyz.zhouxy.plusone.example.ExampleCommand;
@ -358,9 +360,157 @@ public class ArrayPropertyValidatorTests {
// #endregion - allMatch
// ================================
// ================================
// #region - length
// ================================
private static final int MIN_LENGTH = 6;
private static final int MAX_LENGTH = 8;
@Test
void length_specifiedLength_validLength() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, "The length of the array must be 6")
.length(MIN_LENGTH, () -> ExampleException.withMessage("The length of the array must be 6"))
.length(MIN_LENGTH, arr -> ExampleException.withMessage("The length of the array must be 6, but it was %d", arr.length));
}
};
ExampleCommand validCommand = exampleCommandWithStringArrayProperty(6);
assertDoesNotThrow(() -> validator.validate(validCommand));
ExampleCommand commandWithNullStringProperty = exampleCommandWithStringArrayProperty(null);
assertDoesNotThrow(() -> validator.validate(commandWithNullStringProperty));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10 })
void length_specifiedLength_invalidLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, "The length of the array must be 6");
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("The length of the array must be 6", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, () -> ExampleException.withMessage("The length of the array must be 6"));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("The length of the array must be 6", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, arr -> ExampleException.withMessage("The length of the array must be 6, but it was %d", arr.length));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("The length of the array must be 6, but it was %d", length),
specifiedException2.getMessage());
}
@ParameterizedTest
@ValueSource(ints = { 6, 7, 8 })
void length_specifiedMinLengthAndMaxLength_validLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void length_specifiedMinLengthAndMaxLength_null() {
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 9, 10, 11, 12 })
void length_specifiedMinLengthAndMaxLength_invalidLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH));
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("Min length is 6, max length is 8", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("Min length is 6, max length is 8", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("Length of stringArrayProperty is %d, min length is %d, max length is %d", length, MIN_LENGTH, MAX_LENGTH),
specifiedException2.getMessage());
}
// ================================
// #endregion - length
// ================================
static ExampleCommand exampleCommandWithStringArrayProperty(String[] property) {
ExampleCommand exampleCommand = new ExampleCommand();
exampleCommand.setStringArrayProperty(property);
return exampleCommand;
}
static ExampleCommand exampleCommandWithStringArrayProperty(int specifiedLength) {
ExampleCommand exampleCommand = new ExampleCommand();
String[] arr = new String[specifiedLength];
Arrays.fill(arr, "a");
exampleCommand.setStringArrayProperty(arr);
return exampleCommand;
}
}

View File

@ -20,10 +20,13 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import com.google.common.collect.Lists;
@ -362,9 +365,156 @@ public class CollectionPropertyValidatorTests {
// #endregion - allMatch
// ================================
// ================================
// #region - size
// ================================
private static final int MIN_SIZE = 6;
private static final int MAX_SIZE = 8;
@Test
void size_specifiedSize_validSize() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, "The size of the collection must be 6")
.size(MIN_SIZE, () -> ExampleException.withMessage("The size of the collection must be 6"))
.size(MIN_SIZE, c -> ExampleException.withMessage("The size of the collection must be 6, but it was %d", c.size()));
}
};
ExampleCommand validCommand = exampleCommandWithStringListProperty(6);
assertDoesNotThrow(() -> validator.validate(validCommand));
ExampleCommand commandWithNullStringProperty = exampleCommandWithStringListProperty(null);
assertDoesNotThrow(() -> validator.validate(commandWithNullStringProperty));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10 })
void size_specifiedSize_invalidSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, "The size of the collection must be 6");
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("The size of the collection must be 6", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, () -> ExampleException.withMessage("The size of the collection must be 6"));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("The size of the collection must be 6", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, c -> ExampleException.withMessage("The size of the collection must be 6, but it was %d", c.size()));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("The size of the collection must be 6, but it was %d", size),
specifiedException2.getMessage());
}
@ParameterizedTest
@ValueSource(ints = { 6, 7, 8 })
void size_specifiedMinSizeAndMaxSize_validSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void size_specifiedMinSizeAndMaxSize_null() {
ExampleCommand command = exampleCommandWithStringListProperty(null);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 9, 10, 11, 12 })
void size_specifiedMinSizeAndMaxSize_invalidSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE));
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("Min size is 6, max size is 8", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("Min size is 6, max size is 8", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("Size of stringCollectionProperty is %d, min size is %d, max size is %d", size, MIN_SIZE, MAX_SIZE),
specifiedException2.getMessage());
}
// ================================
// #endregion - size
// ================================
static ExampleCommand exampleCommandWithStringListProperty(List<String> property) {
ExampleCommand exampleCommand = new ExampleCommand();
exampleCommand.setStringListProperty(property);
return exampleCommand;
}
static ExampleCommand exampleCommandWithStringListProperty(int specifiedSize) {
ExampleCommand exampleCommand = new ExampleCommand();
String[] arr = new String[specifiedSize];
Arrays.fill(arr, "a");
exampleCommand.setStringListProperty(Arrays.asList(arr));
return exampleCommand;
}
}