8 Commits

Author SHA1 Message Date
483a3d5490 release: 1.0.0-RC3 (plusone/plusone-validator#20 from gitea)
Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:49:50 +08:00
5705686375 fix: 修复 ruleForComparable 无法指定具体类型参数的 BUG (plusone/plusone-validator#19 from gitea)
更新 `BaseComparablePropertyValidator`、`ComparablePropertyValidator`、`BaseValidator` 和 `MapValidator` 中关于 `Comparable` 和 `Range` 的泛型定义

fixes plusone/plusone-validator#14 (gitea)

Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:39:03 +08:00
5b5d7b50d6 docs: 更新示例 (plusone/plusone-validator#18 from gitea)
Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:34:19 +08:00
aad5b6b4fe build: 统一管理依赖版本 (plusone/plusone-validator#17 from gitea)
Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:33:09 +08:00
75a3c7798a chore: 修改 author 信息 (plusone/plusone-validator#16 from gitea)
Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:32:15 +08:00
7d0a25144b chore: 更新项目 URL (plusone/plusone-validator#15 from gitea)
项目 URL 更新为 http://gitea.zhouxy.xyz/plusone/plusone-validator

Co-authored-by: ZhouXY108 <luquanlion@outlook.com>
Co-committed-by: ZhouXY108 <luquanlion@outlook.com>
2025-07-25 17:30:56 +08:00
2977c9a7fb refactor!: 优化二元组校验的 API 设计 2025-07-25 10:57:47 +08:00
09d596b599 feat: 重载 BaseValidator#ruleForPair
- 重载 BaseValidator#ruleForPair,允许传入两个 Function,用于分别从目标对象中获取两个属性
- 升级项目版本至 1.0.0-RC2
2025-07-14 09:43:13 +08:00
27 changed files with 156 additions and 97 deletions

View File

@@ -25,14 +25,9 @@ class CustomerValidator extends BaseValidator<Customer> {
.notNull("生日不能为空") .notNull("生日不能为空")
.must(LocalDate.now().minusYears(16)::isAfter, "用户必须大于16周岁"); .must(LocalDate.now().minusYears(16)::isAfter, "用户必须大于16周岁");
ruleFor(Customer::getAddress).length(20, 250, "地址长度必须在20-250之间"); ruleFor(Customer::getAddress).length(20, 250, "地址长度必须在20-250之间");
ruleFor((Customer customer) -> Pair.of(customer.getVipLevel(), customer.getBirthday())) ruleFor(Customer::getVipLevel, Customer::getBirthday)
.must(CustomerValidator::validateAge, "5级以上会员必须满18周岁"); .must((vipLevel, birthday) -> vipLevel <= 5 || LocalDate.now().minusYears(18).isAfter(birthday),
} "5级以上会员必须满18周岁");
private static boolean validateAge(Pair<Integer, LocalDate> vipLevelAndBirthday) {
Integer vipLevel = vipLevelAndBirthday.getLeft();
LocalDate birthday = vipLevelAndBirthday.getRight();
return vipLevel <= 5 || LocalDate.now().minusYears(18).isAfter(birthday);
} }
public static CustomerValidator getInstance() { public static CustomerValidator getInstance() {
@@ -73,15 +68,9 @@ class CustomerMapValidator extends MapValidator<String, Object> {
.notNull("生日不能为空") .notNull("生日不能为空")
.must(LocalDate.now().minusYears(16)::isAfter, "用户必须大于16周岁"); .must(LocalDate.now().minusYears(16)::isAfter, "用户必须大于16周岁");
ruleForString("address").length(20, 250, "地址长度必须在20-250之间"); ruleForString("address").length(20, 250, "地址长度必须在20-250之间");
this.<Pair<Integer, LocalDate>>ruleFor((Map<String, Object> customer) -> this.<Integer, LocalDate>ruleForPair("vipLevel", "birthday")
Pair.of(MapUtils.getInteger(customer, "vipLevel"), (LocalDate) customer.get("birthday"))) .must((vipLevel, birthday) -> vipLevel <= 5 || LocalDate.now().minusYears(18).isAfter(birthday),
.must(CustomerMapValidator::validateAge, "5级以上会员必须满18周岁"); "5级以上会员必须满18周岁");
}
private static boolean validateAge(Pair<Integer, LocalDate> vipLevelAndBirthday) {
Integer vipLevel = vipLevelAndBirthday.getLeft();
LocalDate birthday = vipLevelAndBirthday.getRight();
return vipLevel <= 5 || LocalDate.now().minusYears(18).isAfter(birthday);
} }
public static CustomerMapValidator getInstance() { public static CustomerMapValidator getInstance() {

View File

@@ -8,28 +8,20 @@
<parent> <parent>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-validator-parent</artifactId> <artifactId>plusone-validator-parent</artifactId>
<version>1.0.0-RC1</version> <version>1.0.0-RC3</version>
</parent> </parent>
<artifactId>plusone-validator</artifactId> <artifactId>plusone-validator</artifactId>
<name>plusone-validator</name> <name>plusone-validator</name>
<url>http://zhouxy.xyz</url>
<description> <description>
Plusone Validator 是一个校验库,使用 lambda 表达式(包括方法引用)和流式 API 构建校验规则,对对象进行校验。 Plusone Validator 是一个校验库,使用 lambda 表达式(包括方法引用)和流式 API 构建校验规则,对对象进行校验。
</description> </description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-commons</artifactId> <artifactId>plusone-commons</artifactId>
<version>1.1.0-RC1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>

View File

@@ -31,7 +31,7 @@ import xyz.zhouxy.plusone.commons.util.AssertTools;
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @param <E> 数组元素的类型 * @param <E> 数组元素的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class ArrayPropertyValidator<T, E> public class ArrayPropertyValidator<T, E>
extends BasePropertyValidator<T, E[], ArrayPropertyValidator<T, E>> { extends BasePropertyValidator<T, E[], ArrayPropertyValidator<T, E>> {

View File

@@ -29,11 +29,11 @@ import com.google.common.collect.Range;
* @param <TProperty> 待校验属性的类型,必须实现 {@code Comparable} 接口 * @param <TProperty> 待校验属性的类型,必须实现 {@code Comparable} 接口
* @param <TPropertyValidator> 具体校验器类型,用于支持链式调用 * @param <TPropertyValidator> 具体校验器类型,用于支持链式调用
* @see Range * @see Range
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public abstract class BaseComparablePropertyValidator< public abstract class BaseComparablePropertyValidator<
T, T,
TProperty extends Comparable<TProperty>, TProperty extends Comparable<? super TProperty>,
TPropertyValidator extends BaseComparablePropertyValidator<T, TProperty, TPropertyValidator>> TPropertyValidator extends BaseComparablePropertyValidator<T, TProperty, TPropertyValidator>>
extends BasePropertyValidator<T, TProperty, TPropertyValidator> { extends BasePropertyValidator<T, TProperty, TPropertyValidator> {
@@ -47,9 +47,9 @@ public abstract class BaseComparablePropertyValidator<
* @param range 区间 * @param range 区间
* @return 当前校验器实例,用于链式调用 * @return 当前校验器实例,用于链式调用
*/ */
public final TPropertyValidator inRange(final Range<TProperty> range) { public final TPropertyValidator inRange(final Range<? super TProperty> range) {
return withRule(Conditions.inRange(range), value -> ValidationException.withMessage( return withRule(Conditions.inRange(range), value -> ValidationException.withMessage(
"The input must in the interval %s. You entered %s.", range, value)); "The input must in the interval %s. You entered %s.", range, value));
} }
/** /**
@@ -60,7 +60,7 @@ public abstract class BaseComparablePropertyValidator<
* @return 当前校验器实例,用于链式调用 * @return 当前校验器实例,用于链式调用
*/ */
public final TPropertyValidator inRange( public final TPropertyValidator inRange(
final Range<TProperty> range, final String errorMessage) { final Range<? super TProperty> range, final String errorMessage) {
return withRule(Conditions.inRange(range), errorMessage); return withRule(Conditions.inRange(range), errorMessage);
} }
@@ -73,7 +73,7 @@ public abstract class BaseComparablePropertyValidator<
* @return 当前校验器实例,用于链式调用 * @return 当前校验器实例,用于链式调用
*/ */
public final <X extends RuntimeException> TPropertyValidator inRange( public final <X extends RuntimeException> TPropertyValidator inRange(
final Range<TProperty> range, final Supplier<X> exceptionSupplier) { final Range<? super TProperty> range, final Supplier<X> exceptionSupplier) {
return withRule(Conditions.inRange(range), exceptionSupplier); return withRule(Conditions.inRange(range), exceptionSupplier);
} }
@@ -86,7 +86,7 @@ public abstract class BaseComparablePropertyValidator<
* @return 当前校验器实例,用于链式调用 * @return 当前校验器实例,用于链式调用
*/ */
public final <X extends RuntimeException> TPropertyValidator inRange( public final <X extends RuntimeException> TPropertyValidator inRange(
final Range<TProperty> range, final Function<TProperty, X> exceptionFunction) { final Range<? super TProperty> range, final Function<TProperty, X> exceptionFunction) {
return withRule(Conditions.inRange(range), exceptionFunction); return withRule(Conditions.inRange(range), exceptionFunction);
} }
@@ -95,8 +95,8 @@ public abstract class BaseComparablePropertyValidator<
*/ */
private static class Conditions { private static class Conditions {
private static <TProperty extends Comparable<TProperty>> Predicate<TProperty> inRange( private static <TProperty extends Comparable<? super TProperty>> Predicate<TProperty> inRange(
final Range<TProperty> range) { final Range<? super TProperty> range) {
return value -> value == null || range.contains(value); return value -> value == null || range.contains(value);
} }
} }

View File

@@ -33,7 +33,7 @@ import java.util.function.Supplier;
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @param <TProperty> 待校验属性的类型 * @param <TProperty> 待校验属性的类型
* @param <TPropertyValidator> 具体校验器类型,用于支持链式调用 * @param <TPropertyValidator> 具体校验器类型,用于支持链式调用
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public abstract class BasePropertyValidator< public abstract class BasePropertyValidator<
T, T,

View File

@@ -19,6 +19,7 @@ package xyz.zhouxy.plusone.validator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@@ -33,7 +34,7 @@ import xyz.zhouxy.plusone.validator.function.*;
* 子类可通过添加不同的校验规则,构建完整的校验逻辑,用于校验对象。 * 子类可通过添加不同的校验规则,构建完整的校验逻辑,用于校验对象。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public abstract class BaseValidator<T> implements IValidator<T> { public abstract class BaseValidator<T> implements IValidator<T> {
@@ -108,7 +109,7 @@ public abstract class BaseValidator<T> implements IValidator<T> {
* 示例:{@code Person::getName}。 * 示例:{@code Person::getName}。
* @return {@code ComparablePropertyValidator}。用于添加针对该属性的校验规则。 * @return {@code ComparablePropertyValidator}。用于添加针对该属性的校验规则。
*/ */
protected final <R extends Comparable<R>> ComparablePropertyValidator<T, R> ruleForComparable( protected final <R extends Comparable<? super R>> ComparablePropertyValidator<T, R> ruleForComparable(
Function<T, R> getter) { Function<T, R> getter) {
ComparablePropertyValidator<T, R> validator = new ComparablePropertyValidator<>(getter); ComparablePropertyValidator<T, R> validator = new ComparablePropertyValidator<>(getter);
this.rules.add(validator::validate); this.rules.add(validator::validate);
@@ -280,13 +281,34 @@ public abstract class BaseValidator<T> implements IValidator<T> {
* @param <V2> 第二个元素的类型 * @param <V2> 第二个元素的类型
* @param getter 根据对象构造一个二元组,通常是两个属性的值。 * @param getter 根据对象构造一个二元组,通常是两个属性的值。
* @return {@code PairPropertyValidator}。用于添加针对该二元组的校验规则。 * @return {@code PairPropertyValidator}。用于添加针对该二元组的校验规则。
*
* @deprecated 请使用 {@link #ruleFor(Function, Function)} 代替。
*/ */
protected final <V1, V2> PairPropertyValidator<T, V1, V2> ruleForPair(Function<T, Entry<V1, V2>> getter) { @Deprecated
protected final <V1, V2> PairPropertyValidator<T, V1, V2> ruleForPair( // NOSONAR
Function<T, Entry<V1, V2>> getter) {
PairPropertyValidator<T, V1, V2> validator = new PairPropertyValidator<>(getter); PairPropertyValidator<T, V1, V2> validator = new PairPropertyValidator<>(getter);
this.rules.add(validator::validate); this.rules.add(validator::validate);
return validator; return validator;
} }
/**
* 添加一个针对二元组的校验器
*
* @param <V1> 第1个元素的类型
* @param <V2> 第2个元素的类型
* @param v1Getter 用于从目标对象获取第1个元素的函数式接口。示例{@code Person::getName1}。
* @param v2Getter 用于从目标对象获取第2个元素的函数式接口。示例{@code Person::getName2}。
* @return {@code PairPropertyValidator}。用于添加针对该二元组的校验规则。
*/
protected final <V1, V2> PairPropertyValidator<T, V1, V2> ruleFor(
Function<T, V1> v1Getter, Function<T, V2> v2Getter) {
PairPropertyValidator<T, V1, V2> validator = new PairPropertyValidator<>(
t -> new SimpleImmutableEntry<>(v1Getter.apply(t), v2Getter.apply(t)));
this.rules.add(validator::validate);
return validator;
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void validate(T obj) { public void validate(T obj) {

View File

@@ -27,7 +27,7 @@ import java.util.function.Supplier;
* 用于构建校验 {@code Boolean} 类型属性的规则链。 * 用于构建校验 {@code Boolean} 类型属性的规则链。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class BoolPropertyValidator<T> public class BoolPropertyValidator<T>
extends BasePropertyValidator<T, Boolean, BoolPropertyValidator<T>> { extends BasePropertyValidator<T, Boolean, BoolPropertyValidator<T>> {

View File

@@ -32,7 +32,7 @@ import xyz.zhouxy.plusone.commons.util.AssertTools;
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @param <E> 集合元素的类型 * @param <E> 集合元素的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class CollectionPropertyValidator<T, E> public class CollectionPropertyValidator<T, E>
extends BasePropertyValidator<T, Collection<E>, CollectionPropertyValidator<T, E>> { extends BasePropertyValidator<T, Collection<E>, CollectionPropertyValidator<T, E>> {

View File

@@ -24,9 +24,9 @@ import java.util.function.Function;
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @param <TProperty> 待校验属性的类型,必须实现 {@code Comparable} 接口 * @param <TProperty> 待校验属性的类型,必须实现 {@code Comparable} 接口
* @see com.google.common.collect.Range * @see com.google.common.collect.Range
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class ComparablePropertyValidator<T, TProperty extends Comparable<TProperty>> public class ComparablePropertyValidator<T, TProperty extends Comparable<? super TProperty>>
extends BaseComparablePropertyValidator<T, TProperty, ComparablePropertyValidator<T, TProperty>> { extends BaseComparablePropertyValidator<T, TProperty, ComparablePropertyValidator<T, TProperty>> {
ComparablePropertyValidator(Function<T, ? extends TProperty> getter) { ComparablePropertyValidator(Function<T, ? extends TProperty> getter) {

View File

@@ -27,7 +27,7 @@ import java.util.function.Supplier;
* 用于构建校验 {@code Double} 类型属性的规则链。 * 用于构建校验 {@code Double} 类型属性的规则链。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class DoublePropertyValidator<T> public class DoublePropertyValidator<T>
extends BaseComparablePropertyValidator<T, Double, DoublePropertyValidator<T>> { extends BaseComparablePropertyValidator<T, Double, DoublePropertyValidator<T>> {

View File

@@ -19,7 +19,7 @@ package xyz.zhouxy.plusone.validator;
/** /**
* 自带校验方法,校验不通过时直接抛异常。 * 自带校验方法,校验不通过时直接抛异常。
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
* *
* @see BaseValidator * @see BaseValidator
*/ */

View File

@@ -23,7 +23,7 @@ package xyz.zhouxy.plusone.validator;
* </p> * </p>
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public interface IValidator<T> { public interface IValidator<T> {

View File

@@ -27,7 +27,7 @@ import java.util.function.Supplier;
* 用于构建校验 {@code Integer} 类型属性的规则链。 * 用于构建校验 {@code Integer} 类型属性的规则链。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class IntPropertyValidator<T> public class IntPropertyValidator<T>
extends BaseComparablePropertyValidator<T, Integer, IntPropertyValidator<T>> { extends BaseComparablePropertyValidator<T, Integer, IntPropertyValidator<T>> {

View File

@@ -27,7 +27,7 @@ import java.util.function.Supplier;
* 用于构建校验 {@code Long} 类型属性的规则链。 * 用于构建校验 {@code Long} 类型属性的规则链。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class LongPropertyValidator<T> public class LongPropertyValidator<T>
extends BaseComparablePropertyValidator<T, Long, LongPropertyValidator<T>> { extends BaseComparablePropertyValidator<T, Long, LongPropertyValidator<T>> {

View File

@@ -16,11 +16,9 @@
package xyz.zhouxy.plusone.validator; package xyz.zhouxy.plusone.validator;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -31,7 +29,7 @@ import java.util.stream.Collectors;
* <p> * <p>
* 校验后拷贝出一个新的 Map 对象,仅保留指定的 key。 * 校验后拷贝出一个新的 Map 对象,仅保留指定的 key。
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public abstract class MapValidator<K, V> extends BaseValidator<Map<K, V>> { public abstract class MapValidator<K, V> extends BaseValidator<Map<K, V>> {
@@ -175,7 +173,8 @@ public abstract class MapValidator<K, V> extends BaseValidator<Map<K, V>> {
* @param key key * @param key key
* @return 属性校验器 * @return 属性校验器
*/ */
protected final <E extends Comparable<E>> ComparablePropertyValidator<Map<K, V>, E> ruleForComparable(K key) { protected final <E extends Comparable<? super E>> //
ComparablePropertyValidator<Map<K, V>, E> ruleForComparable(K key) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Function<Map<K, V>, E> getter = m -> (E) m.get(key); Function<Map<K, V>, E> getter = m -> (E) m.get(key);
return ruleForComparable(getter); return ruleForComparable(getter);
@@ -196,18 +195,19 @@ public abstract class MapValidator<K, V> extends BaseValidator<Map<K, V>> {
/** /**
* 添加一个属性校验器,对指定的两个 key 对应的 value 进行校验 * 添加一个属性校验器,对指定的两个 key 对应的 value 进行校验
* @param <V1> 第个属性的类型 * @param <V1> 第1个属性的类型
* @param <V2> 第个属性的类型 * @param <V2> 第2个属性的类型
* @param k1 第个 key * @param k1 第1个 key
* @param k2 第个 key * @param k2 第2个 key
* @return 属性校验器 * @return 属性校验器
*/ */
protected final <V1 extends V, V2 extends V> protected final <V1 extends V, V2 extends V>
PairPropertyValidator<Map<K, V>, V1, V2> ruleForPair(K k1, K k2) { PairPropertyValidator<Map<K, V>, V1, V2> ruleForPair(K k1, K k2) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Function<Map<K, V>, Entry<V1, V2>> getter = m -> final Function<Map<K, V>, V1> v1Getter = m -> (V1) m.get(k1);
new SimpleImmutableEntry<>((V1) m.get(k1), (V2) m.get(k2)); @SuppressWarnings("unchecked")
return ruleForPair(getter); final Function<Map<K, V>, V2> v2Getter = m -> (V2) m.get(k2);
return ruleFor(v1Getter, v2Getter);
} }
// ================================ // ================================

View File

@@ -23,7 +23,7 @@ import java.util.function.Function;
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @param <TProperty> 待校验属性的类型 * @param <TProperty> 待校验属性的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class ObjectPropertyValidator<T, TProperty> public class ObjectPropertyValidator<T, TProperty>
extends BasePropertyValidator<T, TProperty, ObjectPropertyValidator<T, TProperty>> { extends BasePropertyValidator<T, TProperty, ObjectPropertyValidator<T, TProperty>> {

View File

@@ -27,7 +27,7 @@ import java.util.function.Supplier;
* @param <T> 被验证对象类型 * @param <T> 被验证对象类型
* @param <V1> 第一个元素的类型 * @param <V1> 第一个元素的类型
* @param <V2> 第二个元素的类型 * @param <V2> 第二个元素的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class PairPropertyValidator<T, V1, V2> public class PairPropertyValidator<T, V1, V2>
extends BasePropertyValidator<T, Entry<V1, V2>, PairPropertyValidator<T, V1, V2>> { extends BasePropertyValidator<T, Entry<V1, V2>, PairPropertyValidator<T, V1, V2>> {

View File

@@ -35,7 +35,7 @@ import xyz.zhouxy.plusone.commons.util.StringTools;
* 用于构建校验 {@code String} 类型属性的规则链。 * 用于构建校验 {@code String} 类型属性的规则链。
* *
* @param <T> 待校验对象的类型 * @param <T> 待校验对象的类型
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class StringPropertyValidator<T> public class StringPropertyValidator<T>
extends BaseComparablePropertyValidator<T, String, StringPropertyValidator<T>> { extends BaseComparablePropertyValidator<T, String, StringPropertyValidator<T>> {

View File

@@ -18,7 +18,7 @@ package xyz.zhouxy.plusone.validator;
/** /**
* 校验失败异常 * 校验失败异常
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
public class ValidationException extends RuntimeException { public class ValidationException extends RuntimeException {

View File

@@ -21,7 +21,7 @@ import java.util.function.Function;
/** /**
* Function&lt;T, Boolean&gt; * Function&lt;T, Boolean&gt;
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
@FunctionalInterface @FunctionalInterface
public interface ToBoolObjectFunction<T> extends Function<T, Boolean>, Serializable { public interface ToBoolObjectFunction<T> extends Function<T, Boolean>, Serializable {

View File

@@ -21,7 +21,7 @@ import java.util.function.Function;
/** /**
* Function&lt;T, Double&gt; * Function&lt;T, Double&gt;
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
@FunctionalInterface @FunctionalInterface
public interface ToDoubleObjectFunction<T> extends Function<T, Double>, Serializable { public interface ToDoubleObjectFunction<T> extends Function<T, Double>, Serializable {

View File

@@ -21,7 +21,7 @@ import java.util.function.Function;
/** /**
* Function&lt;T, Integer&gt; * Function&lt;T, Integer&gt;
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
@FunctionalInterface @FunctionalInterface
public interface ToIntegerFunction<T> extends Function<T, Integer>, Serializable { public interface ToIntegerFunction<T> extends Function<T, Integer>, Serializable {

View File

@@ -21,7 +21,7 @@ import java.util.function.Function;
/** /**
* Function&lt;T, Long&gt; * Function&lt;T, Long&gt;
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
@FunctionalInterface @FunctionalInterface
public interface ToLongObjectFunction<T> extends Function<T, Long>, Serializable { public interface ToLongObjectFunction<T> extends Function<T, Long>, Serializable {

View File

@@ -21,7 +21,7 @@ import java.util.function.Function;
/** /**
* Function&lt;T, String&gt; * Function&lt;T, String&gt;
* *
* @author ZhouXY * @author ZhouXY108 <luquanlion@outlook.com>
*/ */
@FunctionalInterface @FunctionalInterface
public interface ToStringFunction<T> extends Function<T, String>, Serializable { public interface ToStringFunction<T> extends Function<T, String>, Serializable {

View File

@@ -31,6 +31,7 @@ import xyz.zhouxy.plusone.validator.BaseValidator;
import xyz.zhouxy.plusone.validator.IValidator; import xyz.zhouxy.plusone.validator.IValidator;
import xyz.zhouxy.plusone.validator.ValidationException; import xyz.zhouxy.plusone.validator.ValidationException;
@SuppressWarnings("deprecation")
public class PairPropertyValidatorTests { public class PairPropertyValidatorTests {
static final String MESSAGE = "Validation failed."; static final String MESSAGE = "Validation failed.";
@@ -41,7 +42,9 @@ public class PairPropertyValidatorTests {
@Test @Test
void must_validInput() { void must_validInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() { ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "100");
IValidator<ExampleCommand> validator1 = new BaseValidator<ExampleCommand>() {
{ {
ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty())) ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty()))
.must((str, intValue) -> Objects.equals(str, intValue.toString())) .must((str, intValue) -> Objects.equals(str, intValue.toString()))
@@ -51,69 +54,113 @@ public class PairPropertyValidatorTests {
(str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue)); (str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue));
} }
}; };
assertDoesNotThrow(() -> validator1.validate(command));
ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "100"); IValidator<ExampleCommand> validator2 = new BaseValidator<ExampleCommand>() {
assertDoesNotThrow(() -> validator.validate(command)); {
ruleFor(ExampleCommand::getStringProperty, ExampleCommand::getIntProperty)
.must((str, intValue) -> Objects.equals(str, intValue.toString()))
.must((str, intValue) -> Objects.equals(str, intValue.toString()), MESSAGE)
.must((str, intValue) -> Objects.equals(str, intValue.toString()), () -> ExampleException.withMessage(MESSAGE))
.must((str, intValue) -> Objects.equals(str, intValue.toString()),
(str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue));
}
};
assertDoesNotThrow(() -> validator2.validate(command));
} }
@Test @Test
void must_default_invalidInput() { void must_default_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() { ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "");
IValidator<ExampleCommand> validator1 = new BaseValidator<ExampleCommand>() {
{ {
ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty())) ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty()))
.must((str, intValue) -> Objects.equals(str, intValue.toString())); .must((str, intValue) -> Objects.equals(str, intValue.toString()));
} }
}; };
ValidationException e1 = assertThrows(ValidationException.class, () -> validator1.validate(command));
assertEquals("The specified condition was not met for the input.", e1.getMessage());
ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, ""); IValidator<ExampleCommand> validator2 = new BaseValidator<ExampleCommand>() {
{
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command)); ruleFor(ExampleCommand::getStringProperty, ExampleCommand::getIntProperty)
assertEquals("The specified condition was not met for the input.", e.getMessage()); .must((str, intValue) -> Objects.equals(str, intValue.toString()));
}
};
ValidationException e2 = assertThrows(ValidationException.class, () -> validator2.validate(command));
assertEquals("The specified condition was not met for the input.", e2.getMessage());
} }
@Test @Test
void must_message_invalidInput() { void must_message_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() { ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "");
IValidator<ExampleCommand> validator1 = new BaseValidator<ExampleCommand>() {
{ {
ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty())) ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty()))
.must((str, intValue) -> Objects.equals(str, intValue.toString()), MESSAGE); .must((str, intValue) -> Objects.equals(str, intValue.toString()), MESSAGE);
} }
}; };
ValidationException e1 = assertThrows(ValidationException.class, () -> validator1.validate(command));
assertEquals(MESSAGE, e1.getMessage());
ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, ""); IValidator<ExampleCommand> validator2 = new BaseValidator<ExampleCommand>() {
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command)); {
assertEquals(MESSAGE, e.getMessage()); ruleFor(ExampleCommand::getStringProperty, ExampleCommand::getIntProperty)
.must((str, intValue) -> Objects.equals(str, intValue.toString()), MESSAGE);
}
};
ValidationException e2 = assertThrows(ValidationException.class, () -> validator2.validate(command));
assertEquals(MESSAGE, e2.getMessage());
} }
@Test @Test
void must_exceptionSupplier_invalidInput() { void must_exceptionSupplier_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() { ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "");
IValidator<ExampleCommand> validator1 = new BaseValidator<ExampleCommand>() {
{ {
ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty())) ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty()))
.must((str, intValue) -> Objects.equals(str, intValue.toString()), () -> ExampleException.withMessage(MESSAGE)); .must((str, intValue) -> Objects.equals(str, intValue.toString()), () -> ExampleException.withMessage(MESSAGE));
} }
}; };
ExampleException e1 = assertThrows(ExampleException.class, () -> validator1.validate(command));
assertEquals(MESSAGE, e1.getMessage());
ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, ""); IValidator<ExampleCommand> validator2 = new BaseValidator<ExampleCommand>() {
{
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command)); ruleFor(ExampleCommand::getStringProperty, ExampleCommand::getIntProperty)
assertEquals(MESSAGE, e.getMessage()); .must((str, intValue) -> Objects.equals(str, intValue.toString()), () -> ExampleException.withMessage(MESSAGE));
}
};
ExampleException e2 = assertThrows(ExampleException.class, () -> validator2.validate(command));
assertEquals(MESSAGE, e2.getMessage());
} }
@Test @Test
void must_exceptionFunction_invalidInput() { void must_exceptionFunction_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() { ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, "");
IValidator<ExampleCommand> validator1 = new BaseValidator<ExampleCommand>() {
{ {
ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty())) ruleForPair((ExampleCommand command) -> new SimpleImmutableEntry<String,Integer>(command.getStringProperty(), command.getIntProperty()))
.must((str, intValue) -> Objects.equals(str, intValue.toString()), .must((str, intValue) -> Objects.equals(str, intValue.toString()),
(str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue)); (str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue));
} }
}; };
ExampleException e1 = assertThrows(ExampleException.class, () -> validator1.validate(command));
assertEquals("Validation failed: ('', 100).", e1.getMessage());
ExampleCommand command = exampleCommandWithIntAndStringListProperty(100, ""); IValidator<ExampleCommand> validator2 = new BaseValidator<ExampleCommand>() {
{
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command)); ruleFor(ExampleCommand::getStringProperty, ExampleCommand::getIntProperty)
assertEquals("Validation failed: ('', 100).", e.getMessage()); .must((str, intValue) -> Objects.equals(str, intValue.toString()),
(str, intValue) -> ExampleException.withMessage("Validation failed: ('%s', %d).", str, intValue));
}
};
ExampleException e2 = assertThrows(ExampleException.class, () -> validator2.validate(command));
assertEquals("Validation failed: ('', 100).", e2.getMessage());
} }
// ================================ // ================================

View File

@@ -122,14 +122,14 @@ class ParamsValidator extends MapValidator<String, Object> {
.notNull(d -> ExampleException.withMessage("The doubleProperty cannot be null, but it was %s", d)); .notNull(d -> ExampleException.withMessage("The doubleProperty cannot be null, but it was %s", d));
ruleForString(STRING_PROPERTY) ruleForString(STRING_PROPERTY)
.notNull(); .notNull();
ruleForComparable(DATE_TIME_PROPERTY) this.<LocalDateTime>ruleForComparable(DATE_TIME_PROPERTY)
.notNull("The dateTimeProperty cannot be null"); .notNull("The dateTimeProperty cannot be null");
ruleFor(OBJECT_PROPERTY) ruleFor(OBJECT_PROPERTY)
.notNull(() -> ExampleException.withMessage("The objectProperty cannot be null")); .notNull(() -> ExampleException.withMessage("The objectProperty cannot be null"));
ruleForCollection(STRING_LIST_PROPERTY) this.<String>ruleForCollection(STRING_LIST_PROPERTY)
.notNull(d -> ExampleException.withMessage("The stringListProperty cannot be null, but it was %s", d)); .notNull(d -> ExampleException.withMessage("The stringListProperty cannot be null, but it was %s", d));
ruleForPair(STRING_PROPERTY, STRING_PROPERTY2) this.<String, String>ruleForPair(STRING_PROPERTY, STRING_PROPERTY2)
.must((str1, str2) -> str1 != null && str1.equals(str2), .must((str1, str2) -> str1 != null && str1.equals(str2),
"'stringProperty' must be equal to 'stringProperty2'."); "'stringProperty' must be equal to 'stringProperty2'.");
} }

15
pom.xml
View File

@@ -6,10 +6,10 @@
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-validator-parent</artifactId> <artifactId>plusone-validator-parent</artifactId>
<version>1.0.0-RC1</version> <version>1.0.0-RC3</version>
<name>plusone-validator-parent</name> <name>plusone-validator-parent</name>
<url>http://zhouxy.xyz</url> <url>http://gitea.zhouxy.xyz/plusone/plusone-validator</url>
<packaging>pom</packaging> <packaging>pom</packaging>
@@ -23,6 +23,10 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<plusone-commons.version>1.1.0-RC1</plusone-commons.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@@ -30,10 +34,15 @@
<dependency> <dependency>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-dependencies</artifactId> <artifactId>plusone-dependencies</artifactId>
<version>1.1.0-RC1</version> <version>${plusone-commons.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-commons</artifactId>
<version>${plusone-commons.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>