一、概述
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
。
0 评论