Bean 验证
“Bean 验证”API 随 Java™ Enterprise Edition 6 平台引入,作为在应用程序的所有层(包括表示层、业务层和数据访问层)中验证 JavaBeans 的标准机制。
在 Bean 验证规范之前,系统在每个层中验证 JavaBeans。为了防止在每个层重新实现验证,开发者直接将验证捆绑到它们的类或者复制验证代码(通常有点混乱)。具有一个为应用程序的所有层所共用的实现,会简化开发者的工作并节省时间。
“Bean 验证”规范定义了用来验证 JavaBeans 以了解数据完整性的元数据模型和 API。元数据源是所定义的约束注释,可以使用 XML 验证描述符来覆盖和扩展这些约束注释。这组 API 使得编程模型易于使用,允许任何应用程序层使用同一组验证约束。验证约束用来检查带注释的字段、方法和类型的值,以确保它们遵从所定义的约束。
约束可以是内置约束或者用户定义的约束。javax.validation.constraints 包中提供了若干内置注释。这些注释用来定义常规约束定义以及用于编写约束。有关内置约束的列表,请参阅 Bean 验证内置约束的相关信息。有关“Bean 验证”元数据模型和 API 的更多详细信息,请参阅“JSR 349 Bean 验证”规范文档。
以下示例是一个使用内置约束注释装饰的简单 Enterprise JavaBeans (EJB) 类。
public class Home {
@Size(Max=20)
String builder;
@NotNull @Size(Max=20)
String address;
public String getAddress() {
return address;
}
public String getBuilder() {
return address;
}
public String setAddress(String newAddress) {
return address = newAddress;
}
public String setBuilder(String newBuilder) {
return builder = newBuilder;
}
}
有关 builder 和 address 的 @Size 注释指定所指定的字符串值不应超过 20 个字符。有关 address 的 @NotNull 注释表明它不能为空。验证 Home 对象之后,会将 builder 值和 address 值传递给为 @Size 注释定义的验证器类。还会将 address 值传递给 @NotNull 验证器类。验证器类将检查适当约束的值,如果任何约束未能通过验证,那么会创建一个 ConstraintViolation 对象,并通过集合返回给验证 Home 对象的调用者。
验证 API
javax.validation 包中包含用于描述如何通过程序来验证 JavaBeans 的“Bean 验证”API。
ConstraintViolation 是用于描述单个约束故障的类。验证对象时会返回一组 ConstraintViolation 类。发生约束违例时,还会显示用于描述该违例的便于阅读的消息。
如果验证期间发生了故障,那么会产生 ValidationException。
“验证器”接口是主要的验证 API,“验证器”实例是能够验证 Java 对象字段、方法和类型的值的对象。引导 API 是用来获取对于 ValidatorFactory 的访问权的机制,ValidatorFactory 可用来创建“验证器”实例。对于部署在该产品上的应用程序,会自动进行引导。应用程序可以通过两种方式来获取验证器或 ValidatorFactory。一种方式是注入(例如,使用 @Resource 注释来注入),另一种方式是使用 java: 查询。
@Resource ValidatorFactory _validatorFactory;
@Resource Validator _validator;
ValidatorFactory validatorFactory = (ValidatorFactory)context.lookup("java:comp/ValidatorFactory");
Validator validator = (Validator)context.lookup("java:comp/Validator");
约束元数据请求 API
元数据 API 支持工具提供者,并且可与其他框架、库和 Java Platform, Enterprise Edition 技术进行集成。可通过所给定类的“验证器”实例来访问对象约束的元数据存储库。
XML 部署描述符
除了在注释中声明约束之外,还支持使用 XML 来声明约束。
验证 XML 描述由两种 XML 文件组成。META-INF/validation.xml 文件描述模块的“Bean 验证”配置。其他 XML 文件类型描述约束声明,并与注释声明方法高度匹配。缺省情况下,对于使用 XML 描述的类将忽略通过注释表示的所有约束声明。通过对 Bean 使用 ignore-annotation="false" 设置,可以强制验证同时使用注释和 XML 约束声明。该产品通过创建特定于包含 XML 描述符的模块的验证器实例,来确保所部署应用程序模块(包含 validation.xml 文件以及在 XML 文件中定义的约束)与其他模块 validation.xml 和约束文件隔离。
高级 Bean 验证概念
“Bean 验证”API 提供了一组内置约束和一个使您能够声明定制约束的接口。这是通过创建约束注释和对 Bean 类型、字段或属性声明注释来实现。编写约束也是通过对另一个约束定义声明约束来实现。
以下示例说明了如何创建 CommentChecker 约束,该约束的定义将确保注释字符串字段不为空。注释文本用方括号括起来,例如,[text]。
package com.my.company;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Constraint(validatedBy = CommentValidator.class)
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface CommentChecker {
String message() default "The comment is not valid.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
…}
package com.my.company;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CommentValidator implements ConstraintValidator<CommentChecker, String> {
public void initialize(CommentChecker arg0) {
}
public boolean isValid(String comment, ConstraintValidatorContext context) {
if (comment == null) {
// Null comment is not allowed, fail the constraint.
return false;
}
if (!comment.contains("[") && !comment.contains("]")) {
// Can't find any open or close brackets, fail the constraint
return false;
}
// Ignore leading and trailing spaces
String trimmedComment = comment.trim();
return // validate '[' prefix condition
trimmedComment.charAt(0) == '[' &&
// validate ']' suffix condition
trimmedComment.charAt(trimmedComment.length()!-1) == ']';
}
}
定义 @CommentChecker 之后,可以将它用来确保根据 CommentValidator isValid() 实现而言,注释字符串字段为有效注释。以下示例说明了 @CommentChecker 约束的用法。验证 myChecker Bean 之后,将由 CommentValidator 类来验证注释字符串以确保满足所定义的约束。package com.my.company;
public myChecker {
@CommentChecker
String comment = null;
...
}
该产品提供了缺省 Bean 验证提供程序,但您可能要在应用程序中使用备用提供程序。您可以通过调用 javax.validation.Validation.byProvider() 方法来创建验证工厂,以编程方式选择备用提供程序。或者,可以通过在 validation.xml 文件中指定 <default-provider/> 元素,以声明方式选择备用提供程序。如果要确保备用提供程序类不与缺省提供程序产生冲突,请将服务器或应用程序类装入器顺序设置为值首先使用本地类装入器来装入类(最后使用父类装入器)。有关如何设置此设置的更多信息,请参阅类装入文档。
“Bean 验证”规范指示是否在类路径中找到了多个 validation.xml 文件以及是否发生了 ValidationException。但是,WebSphere® Application Server 支持这样一个环境:多个团队共同开发将组装并部署到 Application Server 中的模块。在此环境中,将使用同一类装入器来装入应用程序中的所有 EJB 模块,并且可以配置应用程序类装入器,以便通过单个类装入器来装入所有 EJB 模块和 Web 归档 (WAR) 模块。正因为如此,该产品支持多个 validation.xml 文件位于同一类路径中。
<constraint-mapping>META-INF/constraints-house.xml</constaint-mapping>
<constraint-mapping>META-INF/constraints-rooms.xml</constraint-mapping>
当所有“Bean 验证”约束类和配置对于所有应用程序模块都可视时,将不具备此行为。如果在 EAR 文件中定义了单个 validation.xml 文件,并且在模块的类路径中不存在其他可视 validation.xml 文件,那么任何创建验证器工厂或者验证器的模块都将使用该 EAR 文件中定义的 validation.xml 文件。这使得其他模块可以创建将使用另一个模块的 validation.xml 文件的验证器工厂,前提是已经配置类路径以便这两个模块在同一类路径上都可视,并且仅有一个 validation.xml 文件对于这些模块可视。
要更详细地了解“Bean 验证”API 和元数据,请参阅“JSR 349 Bean 验证”规范文档。