概述
误用Bean验证约束是常见的问题。例如,我们可能不小心在一个String
属性上应用了@Future
约束。这样的错误可能导致运行时难以预测的错误。
幸运的是,Hibernate Validator注解处理器能在编译阶段帮助我们检测这些问题。得益于它抛出的错误,我们可以更早地捕捉这些bug。
在本教程中,我们将探讨如何配置处理器,并查看它能为我们发现的一些常见问题。
配置
2.1. 安装
首先,我们需要在pom.xml
中添加注解处理器依赖项:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Averbose=true</arg>
<arg>-AmethodConstraintsSupported=true</arg>
<arg>-AdiagnosticKind=ERROR</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.2.0.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
需要注意的是,这个工具的版本7仅与jakarta.validation约束兼容:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.1</version>
</dependency>
处理器还提供了关于如何在主要Java IDE中设置它的指导。
2.2. 编译器选项
接下来,让我们设置处理器的编译器选项:
<compilerArgs>
<arg>-Averbose=true</arg>
<arg>-AmethodConstraintsSupported=true</arg>
<arg>-AdiagnosticKind=ERROR</arg>
</compilerArgs>
首先,diagnosticKind
选项指定了日志级别。为了在编译时捕获问题,保持默认的ERROR
值更为合适。所有允许的值都在Diagnostic.Kind枚举中引用。
其次,如果我们只想限制对getter方法的约束验证,应将methodConstraintsSupported
选项设置为false
。
在这里,我们将verbose
设置为true
以获取更多输出,但如果我们不希望有大量的日志输出,可以将其设置为false
。
3. 常见约束问题
注解处理器内置了一套预定义的检查错误。让我们通过一个简单的Message
类来深入了解其中的三个问题:
public class Message {
// constructor omitted
}
3.1. 只有getter可以被注解
默认情况下,这个问题不应存在。如名称所示,当我们在非getter方法上注解时会出现这个问题。我们需要将methodConstraintsSupported
选项设置为true
以允许这样做。
让我们在Message
类中添加三个带有注解的方法:
@Min(3)
public boolean broadcast() {
return true;
}
@NotNull
public void archive() {
}
@AssertTrue
public boolean delete() {
return false;
}
然后,我们在配置中设置methodConstraintsSupported
选项为false
:
<compilerArgs>
<arg>AmethodConstraintsSupported=false</arg>
</compilerArgs>
最后,这三个方法会导致处理器检测到问题:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\methodvalidation\model\ReservationManagement.java:[25,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[55,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[38,5] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[47,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[INFO] 4 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.457 s
[INFO] Finished at: 2022-01-20T21:42:47Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.1:compile (default-compile) on project javaxval: Compilation failure: Compilation failure:
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\methodvalidation\model\ReservationManagement.java:[25,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[55,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[38,5] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[47,4] error: Constraint annotations must not be specified at methods, which are no valid JavaBeans getter methods.
有趣的是,即使从技术上讲,delete
方法正确地进行了注解,它也受到了这个问题的影响。
在接下来的章节中,我们将把methodConstraintsSupported
选项重新设置为true
。
3.2. 只有非void方法可以被注解
这个问题指出,我们不应该在void
方法上进行约束验证。我们可以通过在Message
类中注解一个archive
方法来观察这个问题:
@NotNull
public void archive() {
}
这会导致处理器引发错误:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[45,4] error: Void methods may not be annotated with constraint annotations.
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.078 s
[INFO] Finished at: 2022-01-20T21:35:08Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.1:compile (default-compile) on project javaxval: Compilation failure
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[45,4] error: Void methods may not be annotated with constraint annotations.
3.3. 不支持的类型用于注解
这是最常见的问题。当注解目标数据类型与目标属性不匹配时,就会出现这个问题。在Message
类中,我们可以添加一个错误注解的String
属性来看这个问题:
@Past
private String createdAt;
由于@Past
注解,将引发一个错误。实际上,只有日期类型才能使用此约束:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] ${home}\baeldung\tutorials\javaxval\hibernate\validator\ap\Message.java:[20,5] error: The annotation @Past is disallowed for this data type.
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.892 s
[INFO] Finished at: 2022-01-20T21:29:15Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.1:compile (default-compile) on project javaxval: Compilation failure
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[20,5] error: The annotation @Past is disallowed for this data type.
如果我们将错误的注解应用到具有不支持返回类型的函数上,也会得到类似的错误:
@Min(3)
public boolean broadcast() {
return true;
}
处理器的错误消息与前一个相同:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[37,5] error: The annotation @Min is disallowed for the return type of this method.
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.761 s
[INFO] Finished at: 2022-01-20T21:38:28Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.1:compile (default-compile) on project javaxval: Compilation failure
[ERROR] ${home}\baeldung\tutorials\javaxval\src\main\java\com\baeldung\javaxval\hibernate\validator\ap\Message.java:[37,5] error: The annotation @Min is disallowed for the return type of this method.
4. 总结
在这篇文章中,我们尝试了Hibernate Validator注解处理器。
首先,我们安装并配置了它的选项。然后,我们探讨了它在处理三个常见约束问题时的行为。
如往常一样,示例代码可以在GitHub上找到。