在方法參數上使用 @NotNull
一、概述
NullPointerException
是一個常見問題。我們可以保護我們的代碼的一種方法是在我們的方法參數中添加諸如@NotNull
之類的註釋。
通過使用NotNull
,我們表明如果我們想避免異常,我們絕不能使用null
調用我們的方法。然而,就其本身而言,這還不夠。讓我們來了解一下原因。
2. 方法參數上的@NotNull
註解
首先,讓我們創建一個具有簡單返回String
長度的方法的類。
讓我們也為我們的參數添加一個@NotNull
註解:
public class NotNullMethodParameter {
public int validateNotNull(@NotNull String data) {
return data.length();
}
}
當我們導入NotNull, w
我們應該注意@NotNull
註釋有幾種實現。所以,我們需要確保它來自正確的包。
我們將使用javax.validation.constraints
包。
現在,讓我們創建一個NotNullMethodParameter
並使用null
參數調用我們的方法:
NotNullMethodParameter notNullMethodParameter = new NotNullMethodParameter();
notNullMethodParameter.doesNotValidate(null);
儘管我們使用了NotNull
註釋,但我們得到了NullPointerException
:
java.lang.NullPointerException
我們的註釋無效,因為沒有驗證器來強制執行它。
3. 添加驗證者
因此,讓我們添加 Hibernate Validator( javax.validation
參考實現)來識別我們的@NotNull
。
除了我們的驗證器,我們還需要為它用於呈現消息的表達式語言 (EL) 添加一個依賴項:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.3.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
當我們不包含 EL 依賴項時,我們會收到一個ValidationException
來提醒我們:
javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
有了我們的依賴關係,我們可以強制執行我們的@NotNull
註釋。
所以,讓我們使用默認的ValidatorFactory
創建一個驗證器:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
然後,讓我們validate
我們的論點作為我們帶註釋的方法的第一行:
validator.validate(myString);
現在,當我們使用 null 參數調用我們的方法時,我們的@NotNull
被強制執行:
java.lang.IllegalArgumentException: HV000116: The object to be validated must not be null.
這很好,但是必須在每個帶註釋的方法中添加對我們的驗證器的調用會導致大量的樣板文件。
4. 彈簧靴
幸運的是,我們可以在 Spring Boot 應用程序中使用一種更簡單的方法。
4.1。春季啟動驗證
首先,讓我們添加 Maven 依賴項以使用 Spring Boot 進行驗證:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.1</version>
</dependency>
我們的spring-boot-starter-validation
依賴項引入了 Spring Boot 和驗證所需的一切。這意味著我們可以刪除我們之前的 Hibernate 和 EL 依賴項以保持我們的pom.xml
乾淨。
現在,讓我們創建一個 Spring 管理的Component
,確保我們添加了@Validated
**註解**。讓我們使用validateNotNull
方法創建它,該方法接受一個String
參數並返回我們數據的長度,並使用NotNull
註釋我們的參數:
@Component
@Validated
public class ValidatingComponent {
public int validateNotNull(@NotNull String data) {
return data.length();
}
}
最後,讓我們使用自動裝配的ValidatingComponent
創建一個SpringBootTest
。讓我們還添加一個帶有null
作為方法參數的測試:
@SpringBootTest
class ValidatingComponentTest {
@Autowired ValidatingComponent component;
@Test
void givenNull_whenValidate_thenConstraintViolationException() {
assertThrows(ConstraintViolationException.class, () -> component.validate(null));
}
}
我們得到的ConstraintViolationException
具有我們的參數名稱和“不得為空”消息:
javax.validation.ConstraintViolationException: validate.data: must not be null
我們可以在我們的方法約束文章中了解更多關於註釋我們的方法的信息。
4.2.一個警告詞
雖然這適用於我們的public
方法,但讓我們看看當我們添加另一個沒有註釋但調用原始註釋方法的方法時會發生什麼:
public String callAnnotatedMethod(String data) {
return validateNotNull(data);
}
我們的NullPointerException
返回。當我們從同一個類中的另一個方法調用帶註釋的方法時,Spring 不會強制執行NotNull
約束。
4.3. Jakarta 和 Spring Boot 3.0
在 Jakarta 中,驗證包名稱最近從javax.validation
更改為jakarta.validation
。 Spring Boot 3.0 基於 Jakarta ,因此使用較新的jakarta.validation
包。從 7.0.* 及更高版本的hibernate-validator
版本也是如此。這意味著當我們升級時,我們需要更改我們在驗證註釋中使用的包名稱。
5. 結論
在本文中,我們學習瞭如何在標準 Java 應用程序中對方法參數使用@NotNull
註釋。我們還學習瞭如何使用 Spring Boot 的@Validated
註解來簡化我們的 Spring Bean 方法參數驗證,同時也注意到它的局限性。最後,我們注意到當我們將 Spring Boot 項目更新到 3.0 時,我們應該期望將我們的javax
包更改為jakarta
。
像往常一樣,本文中顯示的所有代碼示例都可以在 GitHub 上找到。