使用 springframework 验证错误验证枚举

Validate an Enum with springframework validation Errors

TL;DR:枚举反序列化错误未被 Rest 控制器中的 org.springframework.validation.Errors 捕获

供参考:我们还没有找到一个干净的解决方案,因为我们最终决定,没有人应该告诉我们一个糟糕的枚举


我有一个使用 org.springframework.validation.Errors 进行参数验证的休息控制器:

@RequestMapping(value = "/vol1/frodo")
public ResponseEntity<Object> simpleMethodUsingPost(
        HttpServletRequest httpServletRequest,
        @Valid @RequestBody MySimpleObject simpleObject,
        Errors errors) {

    /* If an error occured, I need to log the object */
    if (errors.hasErrors()) {
        List<FieldError> fields = errors.getFieldErrors();
        doSomething(fields , simpleObject);
    }
}

我的 class MySimpleObject 看起来像这样:

public class MySimpleObject {
    @Valid
    @NotNull(message = "anObjectField is a mandatory field")
    private EmbeddedObject anObjectField = null;

    @Valid
    @NotNull(message = "aStringField is a mandatory field")
    private String aStringField = null;

    @Valid
    private MySimpleEnum aSimpleEnum = null;
}

而我的枚举 class MySimpleEnum 基本上是具有两个值的 class:

public enum MySimpleEnum{

  ORC("ORC"),
  URUK("URUK");

  private String value;

  MySimpleEnum(String value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }
}

此对象的验证(以及 springframework Error 对象中的错误注入)在 StringObject 上运行良好,但验证失败enum 的(因此包含有效注释枚举的对象也会失败)。

在值无效时尝试将 JSON String 转换为枚举失败:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: 
Cannot deserialize value of type 'lotr.middleearth.model.MySimpleEnum' from String "HOBBIT"

如果我使用 ResponseEntityExceptionHandler 并覆盖 handleHttpMessageNotReadable,则会捕获此反序列化错误,但我无法访问其他不同的参数,也无法使用它们。

如何配置 Validatorenumspringframework Error 以便这个异常在我的控制器主体中被捕获并可用?

出现的问题是枚举 MySimpleEnum 中没有常量 "HOBBIT" 可能性是 "ORC" 和 "URUK",在验证问题中可以简单地使用示例:

@NotNull(message = "Custom message")
private MySimpleEnum aSimpleEnum

我最终做了类似的事情来提取请求中有问题的字段:

int start = ex.getMessage().indexOf("[\"");
int end = ex.getMessage().indexOf("\"]");
String fieldName = exception.getMessage().substring(start + 2, end)

该字段恰好位于括号之间消息的末尾。

我并不为那个感到骄傲,它很乱,但它似乎是枚举的唯一方法。

我想最好改用字符串和适当的 Spring 验证,因为它在很大程度上取决于实现,并且可能会随着未来的更新而中断。

我刚遇到同样的问题,但不喜欢向用户提供未格式化的 "ugly" 验证错误消息的想法。

首先,我使枚举 属性 在 pojo 上不可为空。

@NotNull(message = "Type must be NEW_APPLICATION or RENEWAL")
private RegistrationSubmissionTypeEnum type;

然后我更改了 setter 以基本上检查输入(作为字符串)并查看它是否与枚举之一匹配。如果不是,我什么也不做,属性 保持为空,并且它作为验证错误消息之一被报告回来(使用 @NotNull 注释上使用的消息文本)。

public void setType(Object typeInput) {
    for (RegistrationSubmissionTypeEnum typeEnum : RegistrationSubmissionTypeEnum.values()) {
        if (typeEnum.getKey().equalsIgnoreCase(typeInput.toString())) {
            this.type=RegistrationSubmissionTypeEnum.valueOf(typeInput.toString());
        }
    }
}

这才是关键。我们都鄙视的正常行为会生成丑陋的错误消息,但它也会以单独显示此错误消息的方式进行。就个人而言,我喜欢将所有错误一起发回。

我不喜欢在 @NotNull 消息上硬编码枚举值,但在这种特殊情况下(少量枚举值),它比默认枚举序列化错误消息更可取,并且行为one-off 孤立的错误消息。

我考虑过自定义验证器,但开始感觉很沉重。也许有人可以对此进行改进。