假设我有一个简单的POJO,如下所示,用Jackson 2.1和Hibernate Validator 4.3.1注释注释:
final public class Person {
@JsonProperty("nm")
@NotNull
final public String name;
public Person(String name) {
this.name = name;
}
}我像这样向web服务发送JSON:
{"name": null}Hibernate在报告ConstraintViolation时使用类成员标识符"name“而不是JsonProperty注释值。有人知道是否有可能让Hibernate Validator查看类的注释并使用该值吗?
发布于 2013-09-18 21:41:08
不那是不可能的。Hibernate Validator 5 (Bean验证1.1)有ParameterNameProvider的概念,它在违反方法参数约束的情况下将名称返回给报告的名称,但是属性约束没有可比性。
发布于 2017-05-31 10:07:30
不幸的是,没有简单的方法可以做到这一点。但以下是一些可以帮助你的洞察力:
解析约束冲突
在ConstraintViolationException中,您可以获得一组公开约束冲突上下文的ConstraintViolation:
ConstraintViolation#getLeafBean():如果它是bean约束,则此方法返回应用该约束的bean实例。ConstraintViolation#getPropertyPath():返回无效属性的路径。在属性路径中,可以获得叶节点:
Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional =
StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);然后检查节点的类型是否为PROPERTY,并获取其名称:
String nodeName = null;
if (leafNodeOptional.isPresent()) {
Path.Node leafNode = leafNodeOptional.get();
if (ElementKind.PROPERTY == leafNode.getKind()) {
nodeName = leafNode.getName();
}
}与杰克逊一起反思一堂课
要从叶bean类获得可用的JSON属性,可以使用Jackson对其进行内省(有关更多细节,请参见此回答和回答 ):
Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);
BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();然后通过比较叶节点名称和来自Field的BeanPropertyDefinition名称来筛选属性。
Optional<String> jsonProperty = properties.stream()
.filter(property -> nodeName.equals(property.getField().getName()))
.map(BeanPropertyDefinition::getName)
.findFirst();用JAX-RS?
使用JAX(如果您正在使用它),您可以定义一个ExceptionMapper来处理ConstraintViolationException的:
@Provider
public class ConstraintViolationExceptionMapper
implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
...
}
}要在您的ObjectMapper中使用ExceptionMapper,可以为它提供一个ContextResolver:
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = createObjectMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}将Providers接口注入ExceptionMapper中
@Context
private Providers providers;查找ContextResolver,然后获取ObjectMapper实例:
ContextResolver<ObjectMapper> resolver =
providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);如果您对获取@XxxParam名称感兴趣,请参阅此回答。
发布于 2021-03-29 22:24:08
在使用问题模块进行验证时,我已经引发了这个问题-弹簧网,这并不支持开箱即用的bean定义名称hibernate。因此,我想出了下面的逻辑来覆盖createViolation of ConstraintViolationAdviceTrait,并为该字段获取JSONProperty字段名并再次创建违规行为。
public class CustomBeanValidationAdviceTrait implements ValidationAdviceTrait {
private final ObjectMapper objectMapper;
public CustomBeanValidationAdviceTrait(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public Violation createViolation(ConstraintViolation violation) {
String propertyName = getPropertyName(violation.getRootBeanClass(), violation.getPropertyPath().toString());
return new Violation(this.formatFieldName(propertyName), violation.getMessage());
}
private String getPropertyName(Class clazz, String defaultName) {
JavaType type = objectMapper.constructType(clazz);
BeanDescription desc = objectMapper.getSerializationConfig().introspect(type);
return desc.findProperties()
.stream()
.filter(prop -> prop.getInternalName().equals(defaultName))
.map(BeanPropertyDefinition::getName)
.findFirst()
.orElse(defaultName);
}https://stackoverflow.com/questions/18878868
复制相似问题