Hibernate.org Community Documentation

- 上一页
- 下一页

## 第 10 章 Integrating with other frameworks

Hibernate Validator is intended to be used to implement multi-layered data validation, where constraints are expressed in a single place (the annotated domain model) and checked in various different layers of the application. For this reason there are multiple integration points with other technologies.

## 10.1. ORM集成

Hibernate Validator不仅能够和Hibernate集成工作, 还能够和任何JPA的实现很好的一起工作.

## 提示

When lazy loaded associations are supposed to be validated it is recommended to place the constraint on the getter of the association. Hibernate replaces lazy loaded associations with proxy instances which get initialized/loaded when requested via the getter. If, in such a case, the constraint is placed on field level the actual proxy instance is used which will lead to validation errors.

### 10.1.1. 与数据库集成校验

Out of the box, Hibernate (as of version 3.5.x) will translate the constraints you have defined for your entities into mapping metadata. For example, if a property of your entity is annotated `@NotNull`, its columns will be declared as `not null` in the DDL schema generated by Hibernate.

If, for some reason, the feature needs to be disabled, set `hibernate.validator.apply_to_ddl` to `false`. See also 表 2.2 “Bean Validation constraints” and 表 2.3 “Custom constraints”.

你也可以限制这个DDL约束自动生成的特性只应用到一部分实体类. 只需要设置org.hibernate.validator.group.ddl属性, 这个属性的值是你想要应用此特性的实体类的全路径名称, 每个以逗号分隔.

### 10.1.2. 基于Hibernate事件模型的校验

Hibernate Annotations (即 Hibernate 3.5.x) 中包含了一个的Hibernate 事件监听器(译注: 请阅读Hibernate Core文档了解Hibernate的事件模型) - `org.hibernate.cfg.beanvalidation.BeanValidationEventListener` - 来为Hibernate Validator服务. 当一个`PreInsertEvent`, `PreUpdateEvent` 或 `PreDeleteEvent`事件发生的时候, 这个监听器就可以对该事件所涉及到的实体对象进行校验, 如果校验不通过的话, 则抛出异常. 默认情况下, Hibernate在对每个对象进行保存或者修改操作的时候,都会对其进行校验, 而删除操作则不会. 你可以通过javax.persistence.validation.group.pre-persist, javax.persistence.validation.group.pre-update 和 javax.persistence.validation.group.pre-remove属性来定义对应事件发生的时候, 具体要校验哪(些)个校验组, 这个属性的值是要应用的校验组类的全路径, 使用逗号分隔. 例 10.1 “自定义BeanValidationEvenListener”显示了这几个属性在Hibernate内部定义的默认值, 所以, 你不需要在你的应用中再重复定义了.

如果发生了违反约束条件的情况, 该监听器会抛出一个运行时的`ConstraintViolationException`异常, 此异常包含了一系列的`ConstraintViolation`对象用于描述每个违反了约束条件的情况.

如果类路径上有Hibernate Validator, 则Hibernate Annotations (或 Hibernate EntityManager)会自动调用它, 如果你想避免这种情况, 可以设置javax.persistence.validation.mode属性为`none`.

## 注意

如果实体模型上没有定义约束条件, 则不会有任何性能损耗.

如果你想在Hibernate Core中使用上面提到的事件监听器, 则可以在`hibernate.cfg.xml`中定义如下的配置信息:

例 10.1. 自定义`BeanValidationEvenListener`

    <hibernate-configuration>

        <session-factory>

            ...

            <property name="javax.persistence.validation.group.pre-persist">

                javax.validation.groups.Default

            </property>

            <property name="javax.persistence.validation.group.pre-update">

                javax.validation.groups.Default

            </property>

            <property name="javax.persistence.validation.group.pre-remove"></property>

            ...

            <event type="pre-update">

                <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>

            </event>

            <event type="pre-insert">

                <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>

            </event>

            <event type="pre-delete">

                <listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>

            </event>

        </session-factory>

    </hibernate-configuration>

### 10.1.3. JPA

If you are using JPA 2 and Hibernate Validator is in the classpath the JPA2 specification requires that Bean Validation gets enabled. The properties javax.persistence.validation.group.pre-persist, javax.persistence.validation.group.pre-update and javax.persistence.validation.group.pre-remove as described in 第 10.1.2 节 “基于Hibernate事件模型的校验” can in this case be configured in `persistence.xml`. `persistence.xml` also defines a node validation-mode which can be set to `AUTO`, `CALLBACK`, `NONE`. The default is `AUTO`.

对于JPA1来讲, 你需要自己创建和注册Hibernate Validator. 如果你是使用Hibernate EntityManager, 那么你可以把第 10.1.2 节 “基于Hibernate事件模型的校验”中列出来的`BeanValidationEventListener`类添加到你的项目中, 然后再手工注册它.

## 10.2. JSF & Seam

When working with JSF2 or JBoss Seam™ and Hibernate Validator (Bean Validation) is present in the runtime environment, validation is triggered for every field in the application. 例 10.2 “在JSF2中使用Bean Validation” shows an example of the f:validateBean tag in a JSF page. The validationGroups attribute is optional and can be used to specify a comma seperated list of validation groups. The default is `javax.validation.groups.Default`. For more information refer to the Seam documentation or the JSF 2 specification.

例 10.2. 在JSF2中使用Bean Validation

    <h:form>

    <f:validateBean validationGroups="javax.validation.groups.Default">

        <h:inputText value=#{model.property} />

        <h:selectOneRadio value=#{model.radioProperty} > ... </h:selectOneRadio>

        <!-- other input components here -->

    </f:validateBean>

    </h:form>

## 提示

The integration between JSF 2 and Bean Validation is described in the "Bean Validation Integration" chapter of JSR-314. It is interesting to know that JSF 2 implements a custom `MessageInterpolator` to ensure ensure proper localization. To encourage the use of the Bean Validation message facility, JSF 2 will per default only display the generated Bean Validation message. This can, however, be configured via the application resource bundle by providing the following configuration (`{0}` is replaced with the Bean Validation message and `{1}` is replaced with the JSF component label):

    javax.faces.validator.BeanValidator.MESSAGE={1}: {0}

The default is:

    javax.faces.validator.BeanValidator.MESSAGE={0}

## 10.3. CDI

As of version 1.1, Bean Validation is integrated with CDI (Contexts and Dependency Injection for JavaTM EE).

This integration provides CDI managed beans for `Validator` and `ValidatorFactory` and enables dependency injection in constraint validators as well as custom message interpolators, traversable resolvers, constraint validator factories and parameter name providers.

Furthermore, parameter and return value constraints on the methods and constructors of CDI managed beans will automatically be validated upon invocation.

When your application runs on a Jave EE container, this integration is enabled by default. When working with CDI in a Servlet container or in a pure Java SE environment, you can use the CDI portable extension provided by Hibernate Validator. To do so, add the portable extension to your class path as described in 第 1.1.2 节 “CDI”.

### 10.3.1. Dependency injection

CDI's dependency injection mechanism makes it very easy to retrieve `ValidatorFactory` and `Validator` instances and use them in your managed beans. Just annotate instance fields of your bean with `@javax.inject.Inject` as shown in 例 10.3 “Retrieving validator factory and validator via @Inject”.

例 10.3. Retrieving validator factory and validator via `@Inject`

    package org.hibernate.validator.referenceguide.chapter10.cdi.validator;

    @ApplicationScoped

    public class RentalStation {

            @Inject

            private ValidatorFactory validatorFactory;

            @Inject

            private Validator validator;

            //...

    }

The injected beans are the default validator factory and validator instances. In order to configure them - e.g. to use a custom message interpolator - you can use the Bean Validation XML descriptors as discussed in 第 7 章 Configuring via XML.

If you are working with several Bean Validation providers you can make sure that factory and validator from Hibernate Validator are injected by annotating the injection points with the `@HibernateValidator` qualifier which is demonstrated in 例 10.4 “Using the @HibernateValidator qualifier annotation”.

例 10.4. Using the @HibernateValidator qualifier annotation

    package org.hibernate.validator.referenceguide.chapter10.cdi.validator.qualifier;

    @ApplicationScoped

    public class RentalStation {

            @Inject

            @HibernateValidator

            private ValidatorFactory validatorFactory;

            @Inject

            @HibernateValidator

            private Validator validator;

            //...

    }

## 提示

The fully-qualified name of the qualifier annotation is `org.hibernate.validator.cdi.HibernateValidator`. Be sure to not import `org.hibernate.validator.HibernateValidator` instead which is the `ValidationProvider` implementation used for selecting Hibernate Validator when working with the bootstrapping API (see 第 8.1 节 “Retrieving ValidatorFactory and Validator”).

Via `@Inject` you also can inject dependencies into constraint validators and other Bean Validation objects such as `MessageInterpolator` implementations etc.

例 10.5 “Constraint validator with injected bean” demonstrates how an injected CDI bean is used in a `ConstraintValidator` implementation to determine whether the given constraint is valid or not. As the example shows, you also can work with the `@PostConstruct` and `@PreDestroy` callbacks to implement any required construction and destruction logic.

例 10.5. Constraint validator with injected bean

    package org.hibernate.validator.referenceguide.chapter10.cdi.injection;

    public class ValidLicensePlateValidator

                    implements ConstraintValidator<ValidLicensePlate, String> {

            @Inject

            private VehicleRegistry vehicleRegistry;

            @PostConstruct

            public void postConstruct() {

                    //do initialization logic...

            }

            @PreDestroy

            public void preDestroy() {

                    //do destruction logic...

            }

            @Override

            public void initialize(ValidLicensePlate constraintAnnotation) {

            }

            @Override

            public boolean isValid(String licensePlate, ConstraintValidatorContext constraintContext) {

                    return vehicleRegistry.isValidLicensePlate( licensePlate );

            }

    }

### 10.3.2. Method validation

The method interception facilities of CDI allow for a very tight integration with Bean Validation's method validation functionality. Just put constraint annotations to the parameters and return values of the executables of your CDI beans and they will be validated automatically before (parameter constraints) and after (return value constraints) a method or constructor is invoked.

Note that no explicit interceptor binding is required, instead the required method validation interceptor will automatically be registered for all managed beans with constrained methods and constructors.

You can see an example in 例 10.6 “CDI managed beans with method-level constraints”.

例 10.6. CDI managed beans with method-level constraints

    package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation;

    @ApplicationScoped

    public class RentalStation {

            @Valid

            public RentalStation() {

                    //...

            }

            @NotNull

            @Valid

            public Car rentCar(

                            @NotNull Customer customer,

                            @NotNull @Future Date startDate,

                            @Min(1) int durationInDays) {

                    //...

            }

            @NotNull

            List<Car> getAvailableCars() {

                    //...

            }

    }

    package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation;

    @RequestScoped

    public class RentCarRequest {

            @Inject

            private RentalStation rentalStation;

            public void rentCar(String customerId, Date startDate, int duration) {

                    //causes ConstraintViolationException

                    rentalStation.rentCar( null, null, -1 );

            }

    }

Here the `RentalStation` bean hosts several method constraints. When invoking one of the `RentalStation` methods from another bean such as `RentCarRequest`, the constraints of the invoked method are automatically validated. If any illegal parameter values are passed as in the example, a `ConstraintViolationException` will be thrown by the method interceptor, providing detailed information on the violated constraints. The same is the case if the method's return value violates any return value constraints.

Similarly, constructor constraints are validated automatically upon invocation. In the example the `RentalStation` object returned by the constructor will be validated since the constructor return value is marked with `@Valid`.

#### 10.3.2.1. Validated executable types

Bean Validation allows for a fine-grained control of the executable types which are automatically validated. By default, constraints on constructors and non-getter methods are validated. Therefore the `@NotNull` constraint on the method `RentalStation#getAvailableCars()` in 例 10.6 “CDI managed beans with method-level constraints” gets not validated when the method is invoked.

You have the following options to configure which types of executables are validated upon invocation:

- Configure the executable types globally via the XML descriptor `META-INF/validation.xml`; see 第 7.1 节 “Configuring the validator factory in validation.xml” for an example

- Use the `@ValidateOnExecution` annotation on the executable or type level

If several sources of configuration are specified for a given executable, `@ValidateOnExecution` on the executable level takes precedence over `@ValidateOnExecution` on the type level and `@ValidateOnExecution` generally takes precedence over the globally configured types in ``META-INF/validation.xml``.

例 10.7 “Using @ValidateOnExecution” shows how to use the `@ValidateOnExecution` annotation:

例 10.7. Using `@ValidateOnExecution`

    package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation.configuration;

    @ApplicationScoped

    @ValidateOnExecution(type = ExecutableType.ALL)

    public class RentalStation {

            @Valid

            public RentalStation() {

                    //...

            }

            @NotNull

            @Valid

            @ValidateOnExecution(type = ExecutableType.NONE)

            public Car rentCar(

                            @NotNull Customer customer,

                            @NotNull @Future Date startDate,

                            @Min(1) int durationInDays) {

                    //...

            }

            @NotNull

            public List<Car> getAvailableCars() {

                    //...

            }

    }

Here the method `rentCar()` won't be validated upon invocation because it is annotated with `@ValidateOnExecution(type = ExecutableType.NONE)`. In contrast, the constructor and the method `getAvailableCars()` will be validated due to `@ValidateOnExecution(type = ExecutableType.ALL)` being given on the type level. `ExecutableType.ALL` is a more compact form for explicitly specifying all the types `CONSTRUCTORS`, `GETTER_METHODS` and `NON_GETTER_METHODS`.

## 提示

Executable validation can be turned off globally by specifying `<executable-validation enabled="false"/>` in `META-INF/validation.xml`. In this case, any `@ValidateOnExecution` annotations are ignored.

Note that when a method overrides or implements a super-type method the configuration will be taken from that overridden or implemented method (as given via `@ValidateOnExecution` on the method itself or on the super-type). This protects a client of the super-type method from an unexpected alteration of the configuration, e.g. disabling validation of an overridden executable in a sub-type.

In case a CDI managed bean overrides or implements a super-type method and this super-type method hosts any constraints, it can happen that the validation interceptor is not properly registered with the bean, resulting in the bean's methods not being validated upon invocation. In this case you can specify the executable type IMPLICIT on the sub-class as shown in 例 10.8 “Using ExecutableType.IMPLICIT”, which makes sure that all required metadata is discovered an the validation interceptor kicks in when the methods on `ExpressRentalStation` are invoked.

例 10.8. Using `ExecutableType.IMPLICIT`

    package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation.implicit;

    @ValidateOnExecution(type = ExecutableType.ALL)

    public interface RentalStation {

            @NotNull

            @Valid

            Car rentCar(

                            @NotNull Customer customer,

                            @NotNull @Future Date startDate,

                            @Min(1) int durationInDays);

    }

    package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation.implicit;

    @ApplicationScoped

    @ValidateOnExecution(type = ExecutableType.IMPLICIT)

    public class ExpressRentalStation implements RentalStation {

            @Override

            public Car rentCar(Customer customer, Date startDate, @Min(1) int durationInDays) {

                    //...

            }

    }

## 10.4. Java EE

When your application runs on a Java EE application server such as WildFly, you also can obtain `Validator` and `ValidatorFactory` instances via `@Resource` injection in managed objects such as EJBs etc., as shown in 例 10.9 “Retrieving Validator and ValidatorFactory via @Resource injection”.

例 10.9. Retrieving `Validator` and `ValidatorFactory` via `@Resource` injection

    package org.hibernate.validator.referenceguide.chapter10.javaee;

    @Stateless

    public class RentalStationBean {

            @Resource

            private ValidatorFactory validatorFactory;

            @Resource

            private Validator validator;

            //...

    }

Alternatively you can obtain a validator and a validator factory from JNDI under the names "java:comp/Validator" and "java:comp/ValidatorFactory", respectively.

Similar to CDI-based injection via `@Inject`, these objects represent default validator and validator factory and thus can be configured using the XML descriptor `META-INF/validation.xml` (see 第 7 章 Configuring via XML).

When your application is CDI-enabled, the injected objects are CDI-aware as well and e.g. support dependency injection in constraint validators.

版权 © 2009 - 2013 Red Hat, Inc. & Gunnar Morling

- 上一页第 9 章 Using constraint metadata
- 上一级
- 起始页
- 下一页第 11 章 Hibernate Validator Specifics