注释引用的 ConstraintValidator 永远不会被调用,尽管它应该可以工作

A ConstraintValidator referenced by an annotation is never called although it should work

在调试器中,我可以看到注释以某种方式起作用。但是 class AuthorConstraintValidator 的方法 initialize(AuthorConstraint)isValid(Author, ConstraintValidatorContext) 从未被调用。

我搜索了好几个小时来寻找解决方案。但是不知道少了什么

套餐: 休眠核心 5.6.5.Final 休眠验证器 6.2.3.Final

注解@AuthorConstraint

package myapp.entity.author.constraint;

import javax.validation.Constraint;
import javax.validation.Payload;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * An annotation for special constraints of authors.
 */
@Constraint(validatedBy = {AuthorConstraintValidator.class})
@Retention(RUNTIME)
@Target({TYPE})
public @interface AuthorConstraint {
    String message() default "An author needs either a first name or a last name.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

ConstraintValidator 实现

package myapp.entity.author.constraint;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import myapp.entity.author.Author;

/**
 * A validator for special constraints of authors.
 */
public class AuthorConstraintValidator implements ConstraintValidator<AuthorConstraint, Author> {
    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(AuthorConstraint constraintAnnotation) {
    }

    @Override
    public boolean isValid(Author author, ConstraintValidatorContext constraintValidatorContext) {
        if (author == null) {
            return true;
        }

        return author.getFirstName() != null || author.getLastName() != null;
    }
}

作者class

package myapp.entity.author;

import myapp.data.DatedEntity;
import myapp.entity.author.constraint.AuthorConstraint;

import javax.persistence.*;
import java.io.Serializable;

/**
 * Represents an author.
 */
@AuthorConstraint
@Entity
@Table(name = "author")
public class Author extends DatedEntity implements Serializable {
    /**
     * ID associated with an author.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /**
     * First name of an author.
     */
    @Column(name = "first_name")
    private String firstName;

    /**
     * Last name of an author.
     */
    @Column(name = "last_name")
    private String lastName;

    /**
     * Returns the ID associated with an author.
     *
     * @return Primary key of an author.
     */
    public Integer getId() {
        return id;
    }

    /**
     * Sets the ID of an author.
     *
     * @param id the ID of an author
     */
    @SuppressWarnings({"unused", "SameParameterValue"})
    void setId(Integer id) {
        this.id = id;
    }

    /**
     * Returns the first name of an author.
     *
     * @return First name of an author.
     */
    @SuppressWarnings("unused")
    public String getFirstName() {
        return firstName;
    }

    /**
     * Sets the first name of an author.
     *
     * @param firstName first name
     */
    @SuppressWarnings("unused")
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * Returns the last name of an author.
     *
     * @return Last name of an author.
     */
    @SuppressWarnings("unused")
    public String getLastName() {
        return lastName;
    }

    /**
     * Sets the last name of an author.
     *
     * @param lastName last name
     */
    @SuppressWarnings("unused")
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

验证器的测试代码

当我自己创建一个验证器对象时,我可以看到它按预期工作。

Author author = new Author();
AuthorConstraintValidator validator = new AuthorConstraintValidator();

validator.initialize(new AuthorConstraint() {
    @Override
    public Class<? extends Annotation> annotationType() {
        return AuthorConstraint.class;
    }

    @Override
    public String message() {
        return null;
    }

    @Override
    public Class<?>[] groups() {
        return new Class[0];
    }

    @Override
    public Class<? extends Payload>[] payload() {
        return new Class[0];
    }
});

System.err.println(validator.isValid(author, null));
// result: false

您将支持 javax.* 注释的组件与支持 jakarta.* 注释的组件混合在一起。

如果您使用 javax.persistence,您应该使用 javax.validation,因此 Hibernate Validator 6.2.x。它仍然受支持并具有与 HV 7.0.x(针对 Jakarta EE 9,因此 jakarta.validation 包)和即将推出的 HV 8.0.x(针对 Jakarta EE 10)相同的功能).

所以切换到 Hibernate Validator 6.2 和 Bean Validation 2.0。

您还应该检查您的 EL 实现版本。应该是:

  <dependency>
     <groupId>org.glassfish</groupId>
     <artifactId>jakarta.el</artifactId>
     <version>3.0.3</version>
  </dependency>

确保你身边没有其他人,因为他们有很多不同的名字。

然后如果它仍然不起作用,一件事是默认情况下 Hibernate ORM 在尝试初始化 Hibernate Validator 时不会告诉您是否出现问题。

您可以通过将以下属性设置为 CALLBACK:

让它告诉您发生了什么
  • javax.persistence.validation.group.pre-persist
  • javax.persistence.validation.group.pre-update
  • javax.persistence.validation.group.pre-remove