Hibernate validateValue 与值提取器的交互
Hibernate validateValue interaction with value extractor
编辑:错误存在于 6.0.1.Final 而不是 5.4.1.Final。已提交错误报告:https://hibernate.atlassian.net/browse/HV-1471
Hibernate 验证在尝试使用 validateValue 方法时抛出错误
/**
* Validates all constraints placed on the property named {@code propertyName}
* of the class {@code beanType} would the property value be {@code value}.
* <p>
* {@link ConstraintViolation} objects return {@code null} for
* {@link ConstraintViolation#getRootBean()} and
* {@link ConstraintViolation#getLeafBean()}.
*
* @param beanType the bean type
* @param propertyName property to validate
* @param value property value to validate
* @param groups the group or list of groups targeted for validation (defaults to
* {@link Default}).
* @param <T> the type of the object to validate
* @return constraint violations or an empty set if none
* @throws IllegalArgumentException if {@code beanType} is {@code null},
* if {@code propertyName} is {@code null}, empty or not a valid object property
* or if {@code null} is passed to the varargs groups
* @throws ValidationException if a non recoverable error happens
* during the validation process
*/
<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
String propertyName,
Object value,
Class<?>... groups);
问题出现在包含包装属性的 bean 中,在本例中是 JavaFX 的 ObjectProperty<BigInteger>
。验证放置在模型中的字段上,并且 class 验证通过展开属性正确执行。
@NotNull
@Min(value = MINIMUM_ACCEPTABLE_PORT)
@Max(value = MAXIMUM_ACCEPTABLE_PORT)
private ObjectProperty<BigInteger> multicastListenPort = new SimpleObjectProperty<>();
public BigInteger getMulticastListenPort() {
return multicastListenPort.get();
}
public ObjectProperty<BigInteger> multicastListenPortProperty() {
return multicastListenPort;
}
public void setMulticastListenPort(BigInteger multicastListenPort) {
this.multicastListenPort.set(multicastListenPort);
}
验证器实用程序 class:
public static <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
Class<?>... groups) {
Validator validator = getValidator();
return validator.validateValue(beanType, propertyName, value);
}
private static Validator getValidator() {
return Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new PlatformResourceBundleLocator("messages")))
.buildValidatorFactory()
.getValidator();
}
使用 validateValue 时,hibernate 会尝试将提供的值转换为包装器 class 而不是包含的 class,从而导致 class 转换异常。 java.math.BigInteger cannot be cast to javafx.beans.value.ObservableValue
。如果提供的值包装在 SimpleObjectProperty 中,它会在尝试转换之前解包。
调用示例[=19=]
Set<ConstraintViolation<Settings>> violations = ValidationHelper.validateValue(
Settings.class, "multicastListenPort", updatedValue);
将 updatedValue 包装在 SimpleObjectProperty 中(相同的堆栈跟踪,展开并尝试再次展开)
Set<ConstraintViolation<Settings>> violations = ValidationHelper.validateValue(
Settings.class, "multicastListenPort", new SimpleObjectProperty<>(updatedValue));
堆栈跟踪
javax.validation.ValidationException: HV000221: An error occurred while extracting values in value extractor org.hibernate.validator.internal.engine.valueextraction.ObservableValueValueExtractor.
at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper.extractValues(ValueExtractorHelper.java:47) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:104) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:552) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:510) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:479) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:444) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateValueInContext(ValidatorImpl.java:798) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateValue(ValidatorImpl.java:224) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
Caused by: java.lang.ClassCastException: java.math.BigInteger cannot be cast to javafx.beans.value.ObservableValue
at org.hibernate.validator.internal.engine.valueextraction.ObservableValueValueExtractor.extractValues(ObservableValueValueExtractor.java:20) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper.extractValues(ValueExtractorHelper.java:41) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
我确认这是一个错误。威廉打开 https://hibernate.atlassian.net/browse/HV-1471 .
此问题已在 Hibernate Validator 6.0 中修复。2.Final。
编辑:错误存在于 6.0.1.Final 而不是 5.4.1.Final。已提交错误报告:https://hibernate.atlassian.net/browse/HV-1471
Hibernate 验证在尝试使用 validateValue 方法时抛出错误
/**
* Validates all constraints placed on the property named {@code propertyName}
* of the class {@code beanType} would the property value be {@code value}.
* <p>
* {@link ConstraintViolation} objects return {@code null} for
* {@link ConstraintViolation#getRootBean()} and
* {@link ConstraintViolation#getLeafBean()}.
*
* @param beanType the bean type
* @param propertyName property to validate
* @param value property value to validate
* @param groups the group or list of groups targeted for validation (defaults to
* {@link Default}).
* @param <T> the type of the object to validate
* @return constraint violations or an empty set if none
* @throws IllegalArgumentException if {@code beanType} is {@code null},
* if {@code propertyName} is {@code null}, empty or not a valid object property
* or if {@code null} is passed to the varargs groups
* @throws ValidationException if a non recoverable error happens
* during the validation process
*/
<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
String propertyName,
Object value,
Class<?>... groups);
问题出现在包含包装属性的 bean 中,在本例中是 JavaFX 的 ObjectProperty<BigInteger>
。验证放置在模型中的字段上,并且 class 验证通过展开属性正确执行。
@NotNull
@Min(value = MINIMUM_ACCEPTABLE_PORT)
@Max(value = MAXIMUM_ACCEPTABLE_PORT)
private ObjectProperty<BigInteger> multicastListenPort = new SimpleObjectProperty<>();
public BigInteger getMulticastListenPort() {
return multicastListenPort.get();
}
public ObjectProperty<BigInteger> multicastListenPortProperty() {
return multicastListenPort;
}
public void setMulticastListenPort(BigInteger multicastListenPort) {
this.multicastListenPort.set(multicastListenPort);
}
验证器实用程序 class:
public static <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value,
Class<?>... groups) {
Validator validator = getValidator();
return validator.validateValue(beanType, propertyName, value);
}
private static Validator getValidator() {
return Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new PlatformResourceBundleLocator("messages")))
.buildValidatorFactory()
.getValidator();
}
使用 validateValue 时,hibernate 会尝试将提供的值转换为包装器 class 而不是包含的 class,从而导致 class 转换异常。 java.math.BigInteger cannot be cast to javafx.beans.value.ObservableValue
。如果提供的值包装在 SimpleObjectProperty 中,它会在尝试转换之前解包。
调用示例[=19=]
Set<ConstraintViolation<Settings>> violations = ValidationHelper.validateValue(
Settings.class, "multicastListenPort", updatedValue);
将 updatedValue 包装在 SimpleObjectProperty 中(相同的堆栈跟踪,展开并尝试再次展开)
Set<ConstraintViolation<Settings>> violations = ValidationHelper.validateValue(
Settings.class, "multicastListenPort", new SimpleObjectProperty<>(updatedValue));
堆栈跟踪
javax.validation.ValidationException: HV000221: An error occurred while extracting values in value extractor org.hibernate.validator.internal.engine.valueextraction.ObservableValueValueExtractor.
at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper.extractValues(ValueExtractorHelper.java:47) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:104) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:552) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:510) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:479) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:444) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateValueInContext(ValidatorImpl.java:798) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.ValidatorImpl.validateValue(ValidatorImpl.java:224) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
Caused by: java.lang.ClassCastException: java.math.BigInteger cannot be cast to javafx.beans.value.ObservableValue
at org.hibernate.validator.internal.engine.valueextraction.ObservableValueValueExtractor.extractValues(ObservableValueValueExtractor.java:20) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper.extractValues(ValueExtractorHelper.java:41) ~[hibernate-validator-6.0.1.Final.jar:6.0.1.Final]
我确认这是一个错误。威廉打开 https://hibernate.atlassian.net/browse/HV-1471 .
此问题已在 Hibernate Validator 6.0 中修复。2.Final。