您好,登錄后才能下訂單哦!
java 開發中,參數校驗是非常常見的需求。
但是 hibernate-validator 在使用過程中,依然會存在一些問題。
支持 fluent-validation
支持 jsr-303 注解
支持 i18n
支持用戶自定義策略
valid
如今 java 最流行的 hibernate-validator 框架,但是有些場景是無法滿足的。
比如:
驗證新密碼和確認密碼是否相同。(同一對象下的不同屬性之間關系)
當一個屬性值滿足某個條件時,才進行其他值的參數校驗。
其實,在對于多個字段的關聯關系處理時,hibernate-validator 就會比較弱。
本項目結合原有的優點,進行這一點的功能強化。
validation-api 提供了豐富的特性定義,也同時帶來了一個問題。
實現起來,特別復雜。
然而我們實際使用中,常常不需要這么復雜的實現。
valid-api 提供了一套簡化很多的 api,便于用戶自行實現。
hibernate-validator 在使用中,自定義約束實現是基于注解的,針對單個屬性校驗不夠靈活。
本項目中,將屬性校驗約束和注解約束區分開,便于復用和拓展。
hibernate-validator 核心支持的是注解式編程,基于 bean 的校驗。
一個問題是針對屬性校驗不靈活,有時候針對 bean 的校驗,還是要自己寫判斷。
本項目支持 fluent-api 進行過程式編程,同時支持注解式編程。
盡可能兼顧靈活性與便利性。
模塊名稱 | 說明 |
---|---|
valid-api | 核心 api 及注解定義 |
valid-core | 針對 valid-api 的核心實現 |
valid-jsr | 針對 JSR-303 標準注解的實現 |
valid-test | 測試代碼模塊 |
valid-core 默認引入 valid-api
valid-jsr 默認引入 valid-core
JDK1.7+
Maven 3.X+
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>valid-jsr</artifactId>
<version>0.1.2</version>
</dependency>
我們直接利用 jsr 內置的約束類:
public void helloValidTest() {
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertFalse(result.pass());
}
對應日志輸出為:
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預期值為 <not null>,實際值為 <null>', value=null, constraint='NotNullConstraint', expectValue='not null'}], allList=null}
ValidBs 用來進行驗證的引導類,上述的寫法等價于如下:
public void helloValidAllConfigTest() {
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.fail(Fails.failFast())
.group()
.valid(DefaultValidator.getInstance())
.result()
.print();
Assert.assertFalse(result.pass());
}
Object 可以是對象,也可以是普通的值。
constraints 為對應的約束列表,為默認的約束驗證提供便利性。
IConstraint 相關創建工具類 Constraints
、JsrConstraints
可以指定失敗時的處理策略,支持用戶自定義失敗策略。
實現 | 說明 |
---|---|
failOver | 失敗后繼續驗證,直到驗證完所有屬性 |
failFast | 失敗后快速返回 |
有時候我們希望,只驗證指定某一分組的約束。
可以通過 group() 屬性指定,與 IConstraint 中的 group() 屬性匹配的約束才會被執行。
默認為 DefaultValidator,為 valid-api 的實現驗證。
如果你希望使用 jsr-303 注解,可以使用 JsrValidator
。
支持自定義驗證策略。
默認為 simple() 的簡單結果處理。
可以指定為 detail() 進行詳細結果處理查看。
支持用戶自定義結果處理策略。
simple()/detail() 處理的結果為 IResult 實現類。
IResult 支持如下方法:
對結果進行打印,主要便于調試。
對于參數的校驗,一般都是基于異常結合 spring aop來處理的。
throwsEx 會在驗證不通過時,拋出 ValidRuntimeException 異常,對應 message 為提示消息。
@Test(expected = ValidRuntimeException.class)
public void resultThrowsExTest() {
ValidBs.on(null, notNullValidatorEntry())
.valid()
.result()
.throwsEx();
}
上面我們對 ValidBs 有了一個整體的了解,下面來看一看系統內置的屬性約束有哪些。
每個屬性約束都有對應注解。
針對單個屬性,直接使用屬性約束即可,靈活快捷。
針對 bean 校驗,可以結合注解實現,類似于 hibernate-validator。
核心內置屬性約束實現。
枚舉類指定范圍約束
參見工具類 Constraints#enumRangesConstraint
/**
* 枚舉范圍內約束
* (1)當前值必須在枚舉類對應枚舉的 toString() 列表中。
* @param enumClass 枚舉類,不可為空
* @return 約束類
* @since 0.1.1
* @see com.github.houbb.valid.core.annotation.constraint.EnumRanges 枚舉類指定范圍注解
*/
public static IConstraint enumRangesConstraint(final Class<? extends Enum> enumClass)
參見測試類 EnumsRangesConstraintTest
IResult result = ValidBs.on("DEFINE", Constraints.enumRangesConstraint(FailTypeEnum.class))
.result();
Assert.assertFalse(result.pass());
FailTypeEnum 是 valid-api 內置的枚舉類,枚舉值為 FAIL_FAST/FAIL_OVER。
只有屬性值在枚舉值范圍內,驗證才會通過。
指定屬性范圍內約束
參見工具類 Constraints#rangesConstraint
* 值在指定范圍內約束
* (1)這里為了和注解保持一致性,暫時只支持 String
* @param strings 對象范圍
* @return 約束類
* @since 0.1.1
* @see com.github.houbb.valid.core.annotation.constraint.Ranges String 指定范圍內注解
*/
public static IConstraint rangesConstraint(String ... strings)
參見測試類 RangesConstraintTest
IResult result = ValidBs.on("DEFINE", Constraints.rangesConstraint("FAIL_OVER",
"FAIL_FAST"))
.result();
Assert.assertFalse(result.pass());
這個相對于枚舉值,更加靈活一些。
可以根據自己的需要,指定屬性的范圍。
valid-jsr 中內置注解,和 jsr-303 標準一一對應,此處不再贅述。
創建方式見工具類 JsrConstraints
,測試代碼見 xxxConstraintTest。
對應列表如下:
屬性約束 | 注解 | 簡介 |
---|---|---|
AssertFalseConstraint | @AssertFalse | 指定值必須為 false |
AssertTrueConstraint | @AssertTrue | 指定值必須為 true |
MinConstraint | @Min | 指定值必須大于等于最小值 |
MaxConstraint | @Max | 指定值必須小于等于最大值 |
DecimalMinConstraint | @DecimalMin | 指定金額必須大于等于最小值 |
DecimalMaxConstraint | @DecimalMax | 指定金額必須小于等于最大值 |
DigitsConstraint | @Digits | 指定值位數必須符合要求 |
FutureConstraint | @Future | 指定日期必須在未來 |
PastConstraint | @Past | 指定日期必須在過去 |
PatternConstraint | @Pattern | 指定值必須滿足正則表達式 |
SizeConstraint | @Size | 指定值必須在指定大小內 |
實際業務需求的是不斷變化的,內置的屬性約束常常無法滿足我們的實際需求。
我們可以通過自定義屬性,來實現自己的需求。
參見類 DefineConstraintTest
notNullConstraint 對于 null 值是嚴格的。
所以繼承自 AbstractStrictConstraint
,如下:
IResult result = ValidBs.on(null, new AbstractStrictConstraint() {
@Override
protected boolean pass(IConstraintContext context, Object value) {
return value != null;
}
}).result();
Assert.assertFalse(result.pass());
在 jsr-303 標準中,除卻 @NotNull
對于 null 值都是非嚴格校驗的。
繼承自 AbstractConstraint
即可,如下:
IConstraint assertTrueConstraint = new AbstractConstraint<Boolean>() {
@Override
protected boolean pass(IConstraintContext context, Boolean value) {
return false;
}
};
IResult nullValid = ValidBs.on(null, assertTrueConstraint)
.result();
Assert.assertTrue(nullValid.pass());
IResult falseValid = ValidBs.on(false, assertTrueConstraint)
.result();
Assert.assertFalse(falseValid.pass());
注解 | 說明 |
---|---|
@AllEquals | 當前字段及指定字段值必須全部相等 |
@HasNotNull | 當前字段及指定字段值至少有一個不為 null |
@EnumRanges | 當前字段值必須在枚舉屬性范圍內 |
@Ranges | 當前字段值必須在指定屬性范圍內 |
public class User {
/**
* 名稱
*/
@HasNotNull({"nickName"})
private String name;
/**
* 昵稱
*/
private String nickName;
/**
* 原始密碼
*/
@AllEquals("password2")
private String password;
/**
* 新密碼
*/
private String password2;
/**
* 性別
*/
@Ranges({"boy", "girl"})
private String sex;
/**
* 失敗類型枚舉
*/
@EnumRanges(FailTypeEnum.class)
private String failType;
//fluent getter & setter
}
我們限制 name/nickName 至少有一個不為空,password/password2 值要一致。
以及限定了 sex 的范圍值和 failType 的枚舉值。
User user = new User();
user.sex("what").password("old").password2("new")
.failType("DEFINE");
IResult result = ValidBs.on(user)
.fail(Fails.failOver())
.result()
.print();
Assert.assertFalse(result.pass());
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值 <null> 不是預期值', value=null, constraint='HasNotNullConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <old> 不是預期值', value=old, constraint='AllEqualsConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <what> 不是預期值', value=what, constraint='RangesConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <DEFINE> 不是預期值', value=DEFINE, constraint='EnumRangesConstraint', expectValue=''}], allList=null}
與 jsr-303 注解標準保持一致。
為了演示,簡單定義如下:
public class JsrUser {
@Null
private Object nullVal;
@NotNull
private String notNullVal;
@AssertFalse
private boolean assertFalse;
@AssertTrue
private boolean assertTrue;
@Pattern(regexp = "[123456]{2}")
private String pattern;
@Size(min = 2, max = 5)
private String size;
@DecimalMax("12.22")
private BigDecimal decimalMax;
@DecimalMin("1.22")
private BigDecimal decimalMin;
@Min(10)
private long min;
@Max(10)
private long max;
@Past
private Date past;
@Future
private Date future;
@Digits(integer = 2, fraction = 4)
private Long digits;
//fluent getter and setter
}
參見測試類 ValidBsJsrBeanTest
public void beanFailTest() {
Date future = DateUtil.getFormatDate("90190101", DateUtil.PURE_DATE_FORMAT);
Date past = DateUtil.getFormatDate("20190101", DateUtil.PURE_DATE_FORMAT);
JsrUser jsrUser = new JsrUser();
jsrUser.assertFalse(true)
.assertTrue(false)
.decimalMin(new BigDecimal("1"))
.decimalMax(new BigDecimal("55.55"))
.min(5)
.max(20)
.digits(333333L)
.future(past)
.past(future)
.nullVal("123")
.notNullVal(null)
.pattern("asdfasdf")
.size("22222222222222222222");
IResult result = ValidBs.on(jsrUser)
.fail(Fails.failOver())
.valid(JsrValidator.getInstance())
.result()
.print();
Assert.assertFalse(result.pass());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值必須為空', value=123, constraint='NullConstraint', expectValue='null'}, DefaultConstraintResult{pass=false, message='值必須為非空', value=null, constraint='NotNullConstraint', expectValue='not null'}, DefaultConstraintResult{pass=false, message='值必須為假', value=true, constraint='AssertFalseConstraint', expectValue='false'}, DefaultConstraintResult{pass=false, message='值必須為真', value=false, constraint='AssertTrueConstraint', expectValue='true'}, DefaultConstraintResult{pass=false, message='值必須滿足正則表達式', value=asdfasdf, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [123456]{2}'}, DefaultConstraintResult{pass=false, message='值必須為在指定范圍內', value=22222222222222222222, constraint='SizeConstraint', expectValue='大小必須在范圍內 [2, 5]'}, DefaultConstraintResult{pass=false, message='值必須小于金額最大值', value=55.55, constraint='DecimalMaxConstraint', expectValue='小于等于 12.22'}, DefaultConstraintResult{pass=false, message='值必須大于金額最小值', value=1, constraint='DecimalMinConstraint', expectValue='大于等于 1.22'}, DefaultConstraintResult{pass=false, message='值必須大于最小值', value=5, constraint='MinConstraint', expectValue='大于等于 10'}, DefaultConstraintResult{pass=false, message='值必須小于最大值', value=20, constraint='MaxConstraint', expectValue='小于等于 10'}, DefaultConstraintResult{pass=false, message='時間必須在過去', value=Fri Jan 01 00:00:00 CST 9019, constraint='PastConstraint', expectValue='小于等于 Sun Oct 13 12:12:07 CST 2019'}, DefaultConstraintResult{pass=false, message='時間必須在未來', value=Tue Jan 01 00:00:00 CST 2019, constraint='FutureConstraint', expectValue='大于等于 Sun Oct 13 12:12:07 CST 2019'}, DefaultConstraintResult{pass=false, message='值必須滿足位數', value=333333, constraint='DigitsConstraint', expectValue='整數位數 [2], 小數位數 [4]'}], allList=null}
有時候我們一個對象中,會引入其他子對象。
我們希望對子對象也進行相關屬性的驗證,這時候就可以使用 @Valid
注解。
該注解為 jsr-303 標準注解。
public class ValidUser {
/**
* 子節點
*/
@Valid
private User user;
//fluent setter & getter
}
參見測試類 ValidBsValidBeanTest
public void beanFailTest() {
User user = new User();
user.sex("default").password("old").password2("new")
.failType("DEFINE");
ValidUser validUser = new ValidUser();
validUser.user(user);
IResult result = ValidBs.on(validUser)
.fail(Fails.failOver())
.result()
.print();
Assert.assertFalse(result.pass());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='值 <null> 不是預期值', value=null, constraint='HasNotNullConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <old> 不是預期值', value=old, constraint='AllEqualsConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <default> 不是預期值', value=default, constraint='RangesConstraint', expectValue=''}, DefaultConstraintResult{pass=false, message='值 <DEFINE> 不是預期值', value=DEFINE, constraint='EnumRangesConstraint', expectValue=''}], allList=null}
有時候我們可能會引用自身,這個也做了測試,是符合預期的。
參見 ValidBsSelfValidBeanTest
不同國家對于語言的要求肯定也不同。
本項目目前支持中文/英文國際化支持,默認以當前地區編碼為準,如果不存在,則使用英文。
感覺其他語言,暫時使用中沒有用到。(個人也不會,錯了也不知道。暫時不添加)
測試代碼參加 ValidBsI18NTest
public void i18nEnTest() {
Locale.setDefault(Locale.ENGLISH);
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertEquals("Expect is <not null>, but actual is <null>.", result.notPassList().get(0).message());
}
public void i18nZhTest() {
Locale.setDefault(Locale.CHINESE);
IResult result = ValidBs.on(null, JsrConstraints.notNullConstraint())
.result()
.print();
Assert.assertEquals("預期值為 <not null>,實際值為 <null>", result.notPassList().get(0).message());
}
對于不符合約束條件的處理方式,主要有以下兩種:
快速失敗。遇到一個約束不符合條件,直接返回。
優點:耗時較短。
全部驗證,將所有的屬性都驗證一遍。
優點:可以一次性獲得所有失敗信息。
參見工具類 Fails
,返回的實例為單例,且線程安全。
參見測試類 ValidBsFailTest
我們指定要求屬性值長度最小為3,且必須滿足正則表達式。
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3),
JsrConstraints.patternConstraint("[678]{3}"))
.fail(Fails.failFast())
.result()
.print();
Assert.assertEquals(1, result.notPassList().size());
采用快速失敗模式,只有一個失敗驗證結果。
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預期值為 <必須匹配正則表達式 [678]{3}>,實際值為 <12>', value=12, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [678]{3}'}], allList=null}
保持其他部分不變,我們調整下失敗處理策略。
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3),
JsrConstraints.patternConstraint("[678]{3}"))
.fail(Fails.failOver())
.result()
.print();
Assert.assertEquals(2, result.notPassList().size());
此時失敗處理結果為2,日志如下:
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預期值為 <必須匹配正則表達式 [678]{3}>,實際值為 <12>', value=12, constraint='PatternConstraint', expectValue='必須匹配正則表達式 [678]{3}'}, DefaultConstraintResult{pass=false, message='預期值為 <大小必須在范圍內 [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內 [3, 2147483647]'}], allList=null}
為了便于集成不同框架的測試驗證,本框架支持 IValidator。
同時也允許用戶自定義自己的實現方式。
指定 valid 對應的驗證器,通過 ValidBs.valid(IValidator)
方法指定。
默認為 DefaultValidator。
該驗證策略,支持符合 valid-api 的內置注解,及用戶自定義注解。
JsrValidator 支持 jsr-303 標準注解,及 valid-api 標準的相關注解實現和約束實現。
通過 valid 方法指定即可。
IResult result = ValidBs.on(jsrUser)
.valid(JsrValidator.getInstance())
.result()
.print();
如果你想添加自己的實現,直接實現 IValidator,并且在 valid() 中指定即可。
可以參考 DefaultValidator,建議繼承自 AbstractValidator
。
對于驗證的結果,不同的場景,需求也各不相同。
你可能有如下需求:
(1)輸出驗證失敗的信息
(2)輸出所有驗證信息
(3)針對驗證失敗的信息拋出異常
(4)對驗證結果進行自定義處理。
為了滿足上述需求,提供了如下的接口,及內置默認實現。
public interface IResultHandler<T> {
/**
* 對約束結果進行統一處理
* @param constraintResultList 約束結果列表
* @return 結果
*/
T handle(final List<IConstraintResult> constraintResultList);
}
如果你想自定義處理方式,實現此接口。
并在 ValidBs.result(IResultHandler)
方法中指定使用即可。
僅僅對沒有通過測試的驗證結果進行保留。
參見測試代碼 ValidBsResultHandlerTest
ValidBs.on("12", JsrConstraints.sizeConstraintMin(2))
.result(ResultHandlers.simple())
.print();
DefaultResult{pass=true, notPassList=[], allList=null}
保留所有驗證結果信息,包含通過驗證測試的明細信息。
參見測試代碼 ValidBsResultHandlerTest
ValidBs.on("12", JsrConstraints.sizeConstraintMin(2))
.result(ResultHandlers.detail())
.print();
DefaultResult{pass=true, notPassList=[], allList=[DefaultConstraintResult{pass=true, message='null', value=12, constraint='SizeConstraint', expectValue='null'}]}
IResult 為驗證結果處理的內置實現接口。
擁有以下常見方法:
方法 | 說明 |
---|---|
pass() | 是否通過驗證 |
notPassList() | 未通過驗證的列表 |
allList() | 所有驗證的列表 |
print() | 控臺輸出驗證結果 |
throwsEx() | 針對未通過驗證的信息拋出 ValidRuntimeException |
@Test(expected = ValidRuntimeException.class)
public void methodsTest() {
IResult result = ValidBs.on("12", JsrConstraints.sizeConstraintMin(3))
.result(ResultHandlers.detail())
.print()
.throwsEx();
Assert.assertFalse(result.pass());
Assert.assertEquals(1, result.notPassList().size());
Assert.assertEquals(1, result.allList().size());
}
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='預期值為 <大小必須在范圍內 [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內 [3, 2147483647]'}], allList=[DefaultConstraintResult{pass=false, message='預期值為 <大小必須在范圍內 [3, 2147483647]>,實際值為 <2>', value=12, constraint='SizeConstraint', expectValue='大小必須在范圍內 [3, 2147483647]'}]}
Hibernate-validator 主要是基于注解的 Bean 驗證,所以將注解和實現耦合在了一起。
Valid 作為一個 fluent-api 驗證框架,支持過程式編程,所以將針對屬性驗證的約束獨立出來,便于復用。
public interface IConstraint {
/**
* 觸發約束規則
* @param context 上下文
* @return 結果
* @since 0.0.3
*/
IConstraintResult constraint(final IConstraintContext context);
}
前面的例子已經演示了如何自定義實現。
直接實現上述接口也可以,建議繼承 AbstractConstraint
等內置的各種約束抽象類。
當我們將 IConstraint 獨立出來時,同時有下面的一些問題:
(1)如何指定對應 message
(2)如何指定約束生效條件 condition
(3)如何指定約束的分組信息 group
IValidEntry 接口就是為了解決這些問題,在 IConstraint 的基礎之上進行一系列的功能增強。
測試代碼,參見類 ValidBsValidEntryTest
IValidEntry validEntry = ValidEntry.of(JsrConstraints.notNullConstraint());
IResult result = ValidBs.on(null, validEntry)
.result()
.print();
Assert.assertFalse(result.pass());
我們可以自定義改約束條件的提示消息。
final IValidEntry validEntry = ValidEntry.of(JsrConstraints.notNullConstraint())
.message("自定義:指定值不能為空");
IResult result = ValidBs.on(null, validEntry)
.valid()
.result();
Assert.assertEquals("自定義:指定值不能為空", result.notPassList().get(0).message());
有時候我們希望只驗證某一種分組的約束條件。
按照如下方式制定,只有當 ValidEntry 的 group 信息與 ValidBs.group() 符合時,才會被執行。
final IValidEntry firstEntry = ValidEntry.of(JsrConstraints.sizeConstraint(5, 10))
.group(String.class);
final IValidEntry otherEntry = ValidEntry.of(JsrConstraints.sizeConstraint(3, 20))
.group(Integer.class);
IResult result = ValidBs
.on("12", firstEntry, otherEntry)
.fail(Fails.failOver())
.group(String.class)
.result();
Assert.assertEquals(1, result.notPassList().size());
其實可以 group() 只是 condition 的一個特例。
后續將實現 ICondition 接口的相關內置支持,和 @Condition
注解的相關支持。
說到 hibernate-validator,個人覺得最靈魂的設計就是支持用戶自定義注解了。
注解使得使用便利,自定義注解同時保證了靈活性。
下面來看看,如何實現自定義注解。
你可以認為內置注解也是一種自定義注解。
本框架的所有實現理念都是如此,可以認為所有的內置實現,都是可以被替換的。
我們以 @AllEquals
注解為例,
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(AtAllEqualsConstraint.class)
public @interface AllEquals {
/**
* 當前字段及其指定的字段 全部相等
* 1. 字段類型及其他字段相同
* @return 指定的字段列表
*/
String[] value();
/**
* 提示消息
* @return 錯誤提示
*/
String message() default "";
/**
* 分組信息
* @return 分組類
* @since 0.1.2
*/
Class[] group() default {};
}
其中 group()/message() 和 IValidEntry 中的方法一一對應。
當然你設計的注解中如果沒有這兩個方法也沒關系,建議提供這兩個屬性。
@Constraint(AtAllEqualsConstraint.class)
這個注解指定了當前注解與對應的約束實現,是最核心的部分。
@Inherited
@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraint {
/**
* 約束條件實現類
* @return 實現類 class
*/
Class<? extends IAnnotationConstraint> value();
}
這個就是注解相關的約束接口,內容如下:
/**
* 注解約束規則接口
* 注意:所有的實現類都需要提供無參構造函數。
* @author binbin.hou
* @since 0.0.9
*/
public interface IAnnotationConstraint<A extends Annotation> extends IConstraint {
/**
* 初始化映射關系
* @param annotation 注解信息
* @since 0.0.9
*/
void initialize(A annotation);
}
豐富 IConstraintResult 特性
優化 IResult 使用體驗
@Condition 注解支持和 ICondition 的支持。
JSR 380
JSR 303
bean validation 2.0
hibernate validate
apache bval
fluent-validator
FluentValidation
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。