java - 从 Spring BindingResult 到字段 JSONPath/JSON Pointer,与 Jackson

标签 java spring jackson jackson-databind spring-validator

我有一个使用 javax.validation 的 Spring Boot 应用程序注释,我正在尝试返回指向违规字段的友好 JSON 错误消息,但从可用的“Java 对象”路径转换为 ​​JSONPath 或 JSON 指针是我没有找到的方法。
SSCO示例:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;

import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Min;
import java.util.List;

public class Test {

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

        Data data = new Data();
        System.out.println("Serialized: " + mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data));

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        validator.validate(data).forEach(violation -> {
            System.out.println("Path: " + violation.getPropertyPath());
        });
    }

    public static class Data {
        @JsonProperty("foobar")
        @Valid
        public List<Foo> foo = List.of(new Foo());
    }
    public static class Foo {
        @Min(100)
        public int barBaz = 42;
    }

}
输出:
Serialized: {
  "foobar" : [ {
    "bar_baz" : 42
  } ]
}
Path: foo[0].barBaz
如您所见,我需要转换 foo[0].barBaz进入 $.foobar[0].bar_baz/foobar/0/bar_baz .解析的对象(上面的 data 变量)也由 BindingResult 提供保存验证信息的对象。
我想过做一些字符串操作,但这很麻烦,很麻烦,而且很容易被 @JsonProperty 破坏。我需要单独处理,也许是我没有考虑过的其他极端情况。另外,我们使用 SNAKE_CASE作为一个标准,改变以简化任务不是解决方案。
我想 jackson 的 ObjectMapper可以以某种方式用于进行此转换,或使用其他一些 Jackson API,但我找不到任何相关信息。任何其他可以做到这一点的库也很好(理想情况下它应该理解 Jackson 注释,如 @JsonProperty )。

最佳答案

您可以使用 Hibernate Validator 6.1.5 轻松完成。
您需要提供自己的 PropertyNodeNameProvider 实现.

By implementing it, we can define how the name of a property will be resolved during validation. In our case, we want to read the value from the Jackson configuration.


创建 validator :
 ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .propertyNodeNameProvider(new JacksonPropertyNodeNameProvider())
        .buildValidatorFactory();
JacksonPropertyNodeNameProvider:
public class JacksonPropertyNodeNameProvider implements PropertyNodeNameProvider {

  private final ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public String getName(Property property) {
    if ( property instanceof JavaBeanProperty ) {
        return getJavaBeanPropertyName( (JavaBeanProperty) property );
    }

    return getDefaultName( property );
  }

  private String getJavaBeanPropertyName(JavaBeanProperty property) {
    JavaType type = objectMapper.constructType( property.getDeclaringClass() );
    BeanDescription desc = objectMapper.getSerializationConfig().introspect( type );

    return desc.findProperties()
            .stream()
            .filter( prop -> prop.getInternalName().equals( property.getName() ) )
            .map( BeanPropertyDefinition::getName )
            .findFirst()
            .orElse( property.getName() );
  }

  private String getDefaultName(Property property) {
    return property.getName();
  }
}
更多详情您可以在 documentation 中找到:

关于java - 从 Spring BindingResult 到字段 JSONPath/JSON Pointer,与 Jackson,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63248487/

相关文章:

java - JPA 延迟加载在 Spring 引导中不起作用

java - spring MVC3 错误 Could not instantiate bean class [java.util.List] : Specified class is an interface Occasional

java - 无法使用 Jackson 解析 XML,模型永远不会被填充

java - jackson 漂亮的印花绳

java - 在dropwizard项目中使用ehcache

java - SuperClass 属性上的 JPA 覆盖注释

java - 如何禁用Android中的对话框按钮?

java - 使用mapstruct映射不同类型列表的元素

java - 以编程方式设置信任库

java - 使用 Jackson 将 MongoDB 日期字段反序列化为 Java POJO