首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate Validator和Jackson:使用@JsonProperty值作为ConstraintViolation PropertyPath?

Hibernate Validator和Jackson:使用@JsonProperty值作为ConstraintViolation PropertyPath?
EN

Stack Overflow用户
提问于 2013-09-18 17:43:45
回答 3查看 5.5K关注 0票数 7

假设我有一个简单的POJO,如下所示,用Jackson 2.1和Hibernate Validator 4.3.1注释注释:

代码语言:javascript
复制
final public class Person {
  @JsonProperty("nm")
  @NotNull
  final public String name;

  public Person(String name) {
      this.name = name;
  }
}

我像这样向web服务发送JSON:

代码语言:javascript
复制
{"name": null}

Hibernate在报告ConstraintViolation时使用类成员标识符"name“而不是JsonProperty注释值。有人知道是否有可能让Hibernate Validator查看类的注释并使用该值吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-09-18 21:41:08

不那是不可能的。Hibernate Validator 5 (Bean验证1.1)有ParameterNameProvider的概念,它在违反方法参数约束的情况下将名称返回给报告的名称,但是属性约束没有可比性。

票数 3
EN

Stack Overflow用户

发布于 2017-05-31 10:07:30

不幸的是,没有简单的方法可以做到这一点。但以下是一些可以帮助你的洞察力:

解析约束冲突

ConstraintViolationException中,您可以获得一组公开约束冲突上下文的ConstraintViolation

在属性路径中,可以获得叶节点:

代码语言:javascript
复制
Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional = 
        StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);

然后检查节点的类型是否为PROPERTY,并获取其名称:

代码语言:javascript
复制
String nodeName = null;

if (leafNodeOptional.isPresent()) {
    Path.Node leafNode = leafNodeOptional.get();
    if (ElementKind.PROPERTY == leafNode.getKind()) {
        nodeName = leafNode.getName();
    }
}

与杰克逊一起反思一堂课

要从叶bean类获得可用的JSON属性,可以使用Jackson对其进行内省(有关更多细节,请参见此回答回答 ):

代码语言:javascript
复制
Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);

BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();

然后通过比较叶节点名称和来自FieldBeanPropertyDefinition名称来筛选属性。

代码语言:javascript
复制
Optional<String> jsonProperty = properties.stream()
        .filter(property -> nodeName.equals(property.getField().getName()))
        .map(BeanPropertyDefinition::getName)
        .findFirst();

用JAX-RS?

使用JAX(如果您正在使用它),您可以定义一个ExceptionMapper来处理ConstraintViolationException的:

代码语言:javascript
复制
@Provider
public class ConstraintViolationExceptionMapper 
                 implements ExceptionMapper<ConstraintViolationException> {

    @Override
    public Response toResponse(ConstraintViolationException exception) {
        ...
    }
}

要在您的ObjectMapper中使用ExceptionMapper,可以为它提供一个ContextResolver

代码语言:javascript
复制
@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

代码语言:javascript
复制
@Context
private Providers providers;

查找ContextResolver,然后获取ObjectMapper实例:

代码语言:javascript
复制
ContextResolver<ObjectMapper> resolver = 
        providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);

如果您对获取@XxxParam名称感兴趣,请参阅此回答

票数 8
EN

Stack Overflow用户

发布于 2021-03-29 22:24:08

在使用问题模块进行验证时,我已经引发了这个问题-弹簧网,这并不支持开箱即用的bean定义名称hibernate。因此,我想出了下面的逻辑来覆盖createViolation of ConstraintViolationAdviceTrait,并为该字段获取JSONProperty字段名并再次创建违规行为。

代码语言:javascript
复制
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);
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18878868

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档