使用springframework验证错误验证枚举

时间:2018-11-28 17:52:53

标签: java spring error-handling enums exception-handling

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

供参考:我们尚未找到一个干净的解决方案,因为我们最终决定没有人称呼我们为坏枚举


我有一个rest控制器,它使用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);
    }
}

我的课程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;
}

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

public enum MySimpleEnum{

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

  private String value;

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

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

当该对象位于ErrorString上时,此对象的验证(以及在springframework Object对象中注入错误)效果很好,但将无法验证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,则会发现此反序列化错误,但随后我无法访问其他参数,因此无法使用它们。

如何配置 Validator 枚举 springframework错误,以便在控制器主体中捕获并使用此异常? / p>

3 个答案:

答案 0 :(得分:0)

发生的问题是,在枚举MySimpleEnum中没有常量“ HOBBIT”,可能是“ ORC”和“ URUK”,在验证问题中可以像示例中那样简单地使用:

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

答案 1 :(得分:0)

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

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

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

我并不为那件事感到骄傲,这很麻烦,但这似乎是枚举的唯一方法。

我想最好使用字符串和适当的Spring验证,因为它过多地依赖于实现,并且可能在将来的更新中失效。

答案 2 :(得分:0)

我只是遇到了同样的问题,但不喜欢给用户提供未经格式化的“丑陋”的验证错误消息的想法。

首先,我使pojo上的enum属性不可为空。

@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消息上的枚举值进行硬编码,但是在这种特殊情况下(少量的枚举值),它比默认的枚举序列化错误消息更可取,并且具有以下行为:关闭隔离的错误消息。

我考虑了一个自定义验证器,但是开始感到沉重。也许有人可以对此进行改进。