mdr*_*drg 5 java spring jackson spring-validator jackson-databind
我有一个使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Serialized: {
"foobar" : [ {
"bar_baz" : 42
} ]
}
Path: foo[0].barBaz
Run Code Online (Sandbox Code Playgroud)
如您所见,我需要转换foo[0].barBaz为$.foobar[0].bar_baz或/foobar/0/bar_baz。解析的对象(data上面的变量)也由BindingResult保存验证信息的对象提供。
我想过做一些字符串操作,但这很麻烦,很麻烦,而且很容易破坏@JsonProperty,我需要单独处理,也许还有我没有考虑过的其他极端情况。另外,我们使用SNAKE_CASE作为标准,改变以简化任务不是解决方案。
我想杰克逊ObjectMapper可以以某种方式用于进行这种转换,或者杰克逊 API 的其他部分,但我找不到任何关于它的信息。任何其他可以做到这一点的库也很好(理想情况下它应该理解 Jackson 注释,如@JsonProperty)。
您可以使用 Hibernate Validator 6.1.5 轻松完成。
您需要提供自己的PropertyNodeNameProvider.
通过实现它,我们可以定义在验证期间如何解析属性的名称。在我们的例子中,我们想从 Jackson 配置中读取值。
创建验证器:
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.propertyNodeNameProvider(new JacksonPropertyNodeNameProvider())
.buildValidatorFactory();
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
更多细节您可以在文档中找到:
| 归档时间: |
|
| 查看次数: |
683 次 |
| 最近记录: |