如何验证无限通配符元素?
How can I validate an unbounded wildcards elements?
我正在用 spring-boot-starter-web:2.1.6.RELEASE
编写代码,它传递地依赖于 hibernate-validator:6.0.17
。
我得到了以下错误。
java.lang.IllegalArgumentException: HV000116:
type is not a reference type: ? extends java.math.BigDecimal
来自
default @NotNull BigDecimal divide(
@Size(min = 2, max = 2) @NotNull
List<@NotNull ? extends BigDecimal> positioned) {
...
}
特别是来自 <@NotNull ? extends BigDecimal>
.
我做错了什么?
这里是堆栈跟踪
java.lang.IllegalArgumentException: HV000116: type is not a reference type: ? extends java.math.BigDecimal
at org.hibernate.validator.internal.util.Contracts.assertTrue(Contracts.java:73)
at org.hibernate.validator.internal.util.TypeHelper.getErasedReferenceType(TypeHelper.java:193)
at org.hibernate.validator.internal.metadata.core.MetaConstraints.addValueExtractorDescriptorForWrappedValue(MetaConstraints.java:82)
at org.hibernate.validator.internal.metadata.core.MetaConstraints.create(MetaConstraints.java:55)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.createTypeArgumentMetaConstraint(AnnotationMetaDataProvider.java:795)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.lambda$findTypeUseConstraints(AnnotationMetaDataProvider.java:783)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:274)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeUseConstraints(AnnotationMetaDataProvider.java:784)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeArgumentsConstraints(AnnotationMetaDataProvider.java:762)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeAnnotationConstraintsForExecutableParameter(AnnotationMetaDataProvider.java:716)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getParameterMetaData(AnnotationMetaDataProvider.java:429)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findExecutableMetaData(AnnotationMetaDataProvider.java:300)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getMetaData(AnnotationMetaDataProvider.java:285)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getMethodMetaData(AnnotationMetaDataProvider.java:272)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.retrieveBeanConfiguration(AnnotationMetaDataProvider.java:134)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getBeanConfiguration(AnnotationMetaDataProvider.java:124)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanConfigurationForHierarchy(BeanMetaDataManager.java:232)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.createBeanMetaData(BeanMetaDataManager.java:199)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanMetaData(BeanMetaDataManager.java:166)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:265)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:233)
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:112)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
您的用法是正确的。我认为这可能是一个实现错误。
看看hibernate如何解析类型引用TypeHelper#getErasedReferenceType:
public static Class<?> getErasedReferenceType(Type type) {
Contracts.assertTrue( isReferenceType( type ), "type is not a reference type: %s", type );
return (Class<?>) getErasedType( type );
}
isReferenceType
不检查通配符类型 TypeHelper#isReferenceType:
private static boolean isReferenceType(Type type) {
return type == null
|| type instanceof Class<?>
|| type instanceof ParameterizedType
|| type instanceof TypeVariable<?>
|| type instanceof GenericArrayType;
}
因此当休眠尝试验证列表的内容时断言失败(由于<@NotNull ? extends BigDecimal>
)
但不知何故 TypeHelper#getErasedType 支持通配符类型:
public static Type getErasedType(Type type) {
...
if ( type instanceof WildcardType ) {
Type[] upperBounds = ( (WildcardType) type ).getUpperBounds();
return getErasedType( upperBounds[0] );
}
...
}
我会尝试打开一个关于这个的问题。
我正在用 spring-boot-starter-web:2.1.6.RELEASE
编写代码,它传递地依赖于 hibernate-validator:6.0.17
。
我得到了以下错误。
java.lang.IllegalArgumentException: HV000116:
type is not a reference type: ? extends java.math.BigDecimal
来自
default @NotNull BigDecimal divide(
@Size(min = 2, max = 2) @NotNull
List<@NotNull ? extends BigDecimal> positioned) {
...
}
特别是来自 <@NotNull ? extends BigDecimal>
.
我做错了什么?
这里是堆栈跟踪
java.lang.IllegalArgumentException: HV000116: type is not a reference type: ? extends java.math.BigDecimal
at org.hibernate.validator.internal.util.Contracts.assertTrue(Contracts.java:73)
at org.hibernate.validator.internal.util.TypeHelper.getErasedReferenceType(TypeHelper.java:193)
at org.hibernate.validator.internal.metadata.core.MetaConstraints.addValueExtractorDescriptorForWrappedValue(MetaConstraints.java:82)
at org.hibernate.validator.internal.metadata.core.MetaConstraints.create(MetaConstraints.java:55)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.createTypeArgumentMetaConstraint(AnnotationMetaDataProvider.java:795)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.lambda$findTypeUseConstraints(AnnotationMetaDataProvider.java:783)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:274)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeUseConstraints(AnnotationMetaDataProvider.java:784)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeArgumentsConstraints(AnnotationMetaDataProvider.java:762)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findTypeAnnotationConstraintsForExecutableParameter(AnnotationMetaDataProvider.java:716)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getParameterMetaData(AnnotationMetaDataProvider.java:429)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findExecutableMetaData(AnnotationMetaDataProvider.java:300)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getMetaData(AnnotationMetaDataProvider.java:285)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getMethodMetaData(AnnotationMetaDataProvider.java:272)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.retrieveBeanConfiguration(AnnotationMetaDataProvider.java:134)
at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getBeanConfiguration(AnnotationMetaDataProvider.java:124)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanConfigurationForHierarchy(BeanMetaDataManager.java:232)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.createBeanMetaData(BeanMetaDataManager.java:199)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanMetaData(BeanMetaDataManager.java:166)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:265)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:233)
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:112)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
您的用法是正确的。我认为这可能是一个实现错误。
看看hibernate如何解析类型引用TypeHelper#getErasedReferenceType:
public static Class<?> getErasedReferenceType(Type type) {
Contracts.assertTrue( isReferenceType( type ), "type is not a reference type: %s", type );
return (Class<?>) getErasedType( type );
}
isReferenceType
不检查通配符类型 TypeHelper#isReferenceType:
private static boolean isReferenceType(Type type) {
return type == null
|| type instanceof Class<?>
|| type instanceof ParameterizedType
|| type instanceof TypeVariable<?>
|| type instanceof GenericArrayType;
}
因此当休眠尝试验证列表的内容时断言失败(由于<@NotNull ? extends BigDecimal>
)
但不知何故 TypeHelper#getErasedType 支持通配符类型:
public static Type getErasedType(Type type) {
...
if ( type instanceof WildcardType ) {
Type[] upperBounds = ( (WildcardType) type ).getUpperBounds();
return getErasedType( upperBounds[0] );
}
...
}
我会尝试打开一个关于这个的问题。