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

发布于 2025-01-16 20:43:01 字数 4462 浏览 2 评论 0原文

在调试器中,我可以看到注释以某种方式起作用。但 AuthorConstraintValidator 类的 initialize(AuthorConstraint)isValid(Author, ConstraintValidatorContext) 方法永远不会被调用。

我搜索了好几个小时才找到解决方案。但我不知道缺少什么。

套餐: hibernate-core 5.6.5.Final hibernate-validator 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;
    }
}

Author 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

In the debugger, I can see that the annotation somehow works. But the methods initialize(AuthorConstraint) and isValid(Author, ConstraintValidatorContext) of class AuthorConstraintValidator are never called.

I searched for quite a few hours for a solution. But I don’t know what is missing.

Packages:
hibernate-core 5.6.5.Final
hibernate-validator 6.2.3.Final

Annotation @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 implementation

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;
    }
}

Author 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;
    }
}

Test code for validator

When I create a validator object myself, I can see that it works as intended.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遗忘曾经 2025-01-23 20:43:01

您将支持 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

You are mixing components supporting javax.* annotations with components supporting jakarta.* annotations.

If you're using javax.persistence, you should use javax.validation and thus Hibernate Validator 6.2.x. It's still supported and has the same features as HV 7.0.x (which targets Jakarta EE 9 and thus the jakarta.validation package) and the upcoming HV 8.0.x (which targets Jakarta EE 10).

So switch to Hibernate Validator 6.2 and Bean Validation 2.0.

You should also check your version of the EL implementation. It should be:

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

Make sure you don't have another one around as they go with a ton of different names.

Then if it still doesn't work, one thing is that by default Hibernate ORM does not tell you if something is going wrong when it tries to initialize Hibernate Validator.

You can make it tell you what's going on by setting the following properties to CALLBACK:

  • javax.persistence.validation.group.pre-persist
  • javax.persistence.validation.group.pre-update
  • javax.persistence.validation.group.pre-remove
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文