我正在使用JacksonPropertyNodeNameProvider
使用实际的json字段名称而不是Java类字段名称来呈现错误,即account_id
而不是accountId
。我想在多个字段上进行验证时添加了一个自定义约束。当我添加自定义错误时
context.buildConstraintViolationWithTemplate("customField is a mandatory unique attribute")
.addPropertyNode("customField").addBeanNode().addConstraintViolation();
它只在错误而不是custom_field中返回customField
。如果我尝试将PropertNode设置为custom_field
,则会出现ISE错误。是否需要设置某些配置或需要执行其他操作才能使此工作正常进行?这就是初始化验证器的方式。
@Bean
public Validator validator(@Autowired ObjectMapper objectMapper) {
JacksonPropertyNodeNameProvider propertyNodeNameProvider = new JacksonPropertyNodeNameProvider(objectMapper);
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
.propertyNodeNameProvider(propertyNodeNameProvider)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
我现在想出的唯一方法是在返回响应之前手动检索fieldNames。这是一个骇人听闻的解决方案,但找不到其他方法。原因是org.springframework.validation.beanvalidation.SpringValidatorAdapter#getRejectedValue
使用getPropertyAccessor().getPropertyValue(field)
来获取拒绝的值,并且它必须具有确切的fieldName才能起作用。
@ControllerAdvice
public class RestControllerExceptionHandler
extends ResponseEntityExceptionHandler {
@Autowired
PropertyNodeNameProvider provider;
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(INVALID_INPUT.getType(), INVALID_INPUT.getMessage())
ex.getBindingResult().getAllErrors().forEach(e -> {
if (e instanceof FieldError) {
FieldError fe = (FieldError) e;
//Manually find the equivalent json property.
var cv = fe.unwrap(ConstraintViolationImpl.class);
var field_name = provider.getName(new JavaBeanPropertyImpl(cv.getRootBeanClass(), fe.getField()));
errorResponse.addError(field_name, fe.getDefaultMessage());
}
});
return new ResponseEntity<>(errorResponse, INVALID_INPUT.getStatus());
}
private static class JavaBeanPropertyImpl
implements JavaBeanProperty {
private final Class<?> declaringClass;
private final String name;
private JavaBeanPropertyImpl(Class<?> declaringClass, String name) {
this.declaringClass = declaringClass;
this.name = name;
}
@Override
public Class<?> getDeclaringClass() {
return declaringClass;
}
@Override
public String getName() {
return name;
}
}
}