使用 Hibernate Validator 在没有 JavaBean 约定的情况下验证 POJO

Validate POJO without JavaBean conventions with Hibernate Validator

有一个广泛使用 Google AutoValue to create value classes which do not adhere to the JavaBean conventions, i. e. instead of getFoo(), the corresponding method would be named simply foo(). Unfortunately, Hibernate Validator 的代码库只验证开箱即用的 JavaBean getter 或 class 属性,因此 AutoValue classes 的验证会默默地失败。

我如何自定义 Hibernate Validator 来验证不遵守 JavaBean 约定的 POJO(即使用 getsetis/has 前缀)?

示例:

HibernateValidatorAutoValueTest.java

import com.google.auto.value.AutoValue;
import org.hibernate.validator.constraints.NotBlank;
import org.junit.Test;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class HibernateValidatorAutoValueTest {
    @Test
    public void test() {
        final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        final Validator validator = factory.getValidator();

        final Bean validBean = Bean.create("Valid", 100);
        assertTrue("Valid bean should not have constraint violations", validator.validate(validBean).isEmpty());

        final Bean invalidBean = Bean.create("", -1);
        assertFalse("Invalid bean should have constraint violations", validator.validate(invalidBean).isEmpty());
    }

    @AutoValue
    public static abstract class Bean {
        @NotBlank
        public abstract String text();

        @NotNull
        @Min(42L)
        public abstract Integer number();

        public static Bean create(String text, Integer number) {
            return new AutoValue_HibernateValidatorAutoValueTest_Bean(text, number);
        }
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <prerequisites>
        <maven>3.0.1</maven>
    </prerequisites>

    <groupId>org.example</groupId>
    <artifactId>hibernate-validator-auto-value</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.3.4.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.google.auto.value</groupId>
            <artifactId>auto-value</artifactId>
            <version>1.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

现在还不可能,Bean Validation 确实以 JavaBeans 为中心。如果您愿意,请在我们的 JIRA 中提交问题,以便我们可以在参考实现中对其进行探索,但这需要进行相当多的更改。

目前可能的解决方法是使用 XML 或 HV 编程 API 进行约束声明,以将约束应用于这些类型的生成实现的字段。不过,这意味着字段访问优于 getter 访问,当然,它不如将约束直接放在自动值类型的 getter 定义中那么简洁。