注释引用的 ConstraintValidator 永远不会被调用,尽管它应该可以工作
在调试器中,我可以看到注释以某种方式起作用。但 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您将支持
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 实现的版本。应该是:
确保你周围没有另一个,因为它们有很多不同的名字。
然后,如果它仍然不起作用,有一件事是默认情况下 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 supportingjakarta.*
annotations.If you're using
javax.persistence
, you should usejavax.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 thejakarta.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:
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