Spring 控制器中的 JSR-303 验证并获取 @JsonProperty 名称

问题描述 投票:0回答:4

我在 Spring 应用程序中使用

JSR-303
进行验证,它可以根据需要工作。

这是一个例子:

@Column(nullable = false, name = "name")
    @JsonProperty("customer_name")
    @NotEmpty
    @Size(min = 3, max = 32)
    private String name;

并且 REST API 客户端使用

customer_name
作为发送到 API bud 验证字段错误的输入字段名称
org.springframework.validation.FieldError
返回
name
作为字段名称。

是否有某种方法可以获取

JSON-ish
中指定的
@JsonProperty
名称?或者我是否必须实现自己的映射器才能将类字段名称映射到其 JSON 替代方案?

Edit1:将类字段重命名为与 JSON 名称相对应的名称不是替代方案(出于多种原因)。

java validation mapping bean-validation
4个回答
5
投票

现在可以使用 PropertyNodeNameProvider 来完成此操作。


0
投票

目前还没有办法实现这一点。我们在参考实现中遇到了一个问题:HV-823

这将解决 Hibernate Validator 方面的问题(即返回您期望的名称

Path.Node#getName()
),它需要更多检查 Spring 是否确实从那里获取名称。

也许您有兴趣帮助实现这个?


0
投票

对于

MethodArgumentNotValidException
BindException
我编写了一个方法,尝试通过反射从 Spring
ConstraintViolation
访问私有
ViolationFieldError

  /**
   * Try to get the @JsonProperty annotation value from the field. If not present then the
   * fieldError.getField() is returned.
   * @param fieldError {@link FieldError}
   * @return fieldName
   */
  private String getJsonFieldName(final FieldError fieldError) {
    try {
      final Field violation = fieldError.getClass().getDeclaredField("violation");
      violation.setAccessible(true);
      var constraintViolation = (ConstraintViolation) violation.get(fieldError);
      final Field declaredField = constraintViolation.getRootBeanClass()
          .getDeclaredField(fieldError.getField());
      final JsonProperty annotation = declaredField.getAnnotation(JsonProperty.class);
      //Check if JsonProperty annotation is present and if value is set
      if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
        return annotation.value();
      } else {
        return fieldError.getField();
      }
    } catch (Exception e) {
      return fieldError.getField();
    }
  }

此代码可用于处理具有

@ExceptionHandler(BindException.class)
的类中的 BindExceptions
@ControllerAdvice
的方法:

@ControllerAdvice
public class ControllerExceptionHandler {

  @ExceptionHandler(BindException.class)
  public ResponseEntity<YourErrorResultModel> handleBindException(final BindException exception) {
    for (FieldError fieldError : exception.getBindingResult().getFieldErrors()) {
      final String fieldName = getJsonFieldName(fieldError);
   ...
}

0
投票

这是从

@JsonProperty
注释获取值的函数。

private String getJsonPropertyValue(final FieldError error) {
    try {
        if (error.contains(ConstraintViolation.class)) {
            final ConstraintViolation<?> violation = error.unwrap(ConstraintViolation.class);
            final Field declaredField = violation.getRootBeanClass().getDeclaredField(error.getField());
            final JsonProperty annotation = declaredField.getAnnotation(JsonProperty.class);

            if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
                return annotation.value();
            }
        }
    } catch (Exception ignored) {
    }

    return error.getField();
}

然后在你的异常处理程序中

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<?> validationExceptionHandler(MethodArgumentNotValidException e) {
    final Map<String, String> errors = new HashMap<>();
    e.getBindingResult().getAllErrors().forEach((error) -> {
        String fieldName = getJsonPropertyValue((FieldError) error);
        String errorMessage = error.getDefaultMessage();
        errors.put(fieldName, errorMessage);
    });
    System.out.println(errors); // put this in your response
    return ResponseEntity.badRequest().build();
}
© www.soinside.com 2019 - 2024. All rights reserved.