@NotNull、@NotBlack等校驗注解的詭異問題總結
- 問題再現
-
- 背景
- 複現
- 錯誤提示
- 解決
-
- 查找問題過程
- 解決方案
- PS
問題再現
背景
公司新成立了一個項目,但在已有項目的支援下引入了一批原始的依賴,就這樣,坑來了…
複現
-
通過Maven工具引入java注解相關依賴.
僅展示與@NotNull和@NotBlank相關的依賴,友善後續作說明.
<!--注解校驗類-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<!--<version>2.0.1.Final</version>-->
</dependency>
<!--以下注解校驗實作類-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!--以上注解校驗實作類-->
- 代碼實作(涉及公司機密,是以僅展示Demo)
2.1 請求Request
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
//校驗實體類
@Data
public class SSS {
@NotEmpty(message = "名稱不能為空!")
private String name;
@NotNull(message = "年齡不能為空!")
@Min(message = "年齡不能小于123歲!", value = 123)
private Integer age;
}
2.2 請求Controller
@RestController
@RequestMapping("/test")
public class InfoController {
@PostMapping("/demo")
public String ss( @Valid @RequestBody SSS request) {
System.out.println(request.toString());
return "測試成功";
}
}
錯誤提示
- java: The annotation @NotEmpty is disallowed for this data type.
@NotEmpty\@NotBlank等注解用在字元串屬性上提示[The annotation XXX is disallowed for this data type]的問題解決方案.問題再現解決
解決
查找問題過程
通過錯誤提示[is disallowed for this data type.]對代碼的全局搜尋後,發現【hibernate-validator】依賴的【ValidationProcessorMessages.properties】中存在【NOT_SUPPORTED_TYPE=The annotation @{0} is disallowed for this data type.】,再通過引用方式點選進入【TypeCheck.java】類中才發現該依賴會對屬性在編譯時期就進行類型比對的校驗,且其并未完全參照@NotEmpty等注解的支援形式進行類型判斷,是以會提示該錯誤;
例:@NotEmpty與本注解會支援下列屬性
CharSequence (length of character sequence is evaluated)
Collection (collection size is evaluated)
Map (map size is evaluated)
Array (array length is evaluated)
上述描述如圖 1.1、1.2所示.
圖1.1 ValidationProcessorMessages.properties部分消息展示
圖1.2 TypeCheck.java校驗邏輯
解決方案
既然原有的【hibernate-validator】并不滿足@NotEmpty和@NotBlank等方式編譯期校驗,即可以再尋找替換的方案;而Spring提供的【spring-boot-starter-validation】依賴經測試可以滿足,原因很簡單,就是它實作了上述注解的适用範圍.直接使用【spring-boot-starter-validation】替換maven依賴的【hibernate-validator】和【hibernate-validator-annotation-processor】即可。
替換依賴如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
這樣即可解決題目中出現的錯誤了
PS
1.其實springboot的校驗實作基類都是以【HibernateValidatorFactory.java】進行校驗邏輯對象的調用,無非是筆者最先引入的依賴多了一個TypeCheck的校驗罷了。
2.附上筆者親測的@NotEmpty這一系列的注解最終的處理方式。
…
1.通過BindingResult進行校驗結果處理;(其實可以使用切面進行處理,至于實作就靠各位了.)
@PostMapping("/test")
public String ss( @RequestAttribute SSS request, BindingResult rs ) {
//此處處理校驗結果.
if(rs.hasErrors()){
//每次僅取一次校驗結果傳回.
return rs.getFieldError().getDefaultMessage();
}
System.out.println(request.toString());
return "dafds";
}
2.通過@Valid注解抛出校驗異常,再用@RestControllerAdvice結合@ExceptionHandler進行統一異常處理,Demo如下.
@PostMapping("/test")
public String ss(@Valid @RequestAttribute SSS request) {
//此處處理校驗結果.
if(rs.hasErrors()){
//每次僅取一次校驗結果傳回.
return rs.getFieldError().getDefaultMessage();
}
System.out.println(request.toString());
return "dafds";
}
//統一異常處理類
@RestControllerAdvice
public class BaseExceptionHandler {
/**
* 業務手動異常
*/
@ExceptionHandler(value = Exception.class)
public String exceptionRest(Exception e) {
return e.getMessage();
}
先就這樣吧。