没有找到用于枚举 springboot 的自定义注释和验证的验证器 java8

no validator found for custom annotation and validation for enum springboot java8

出现此错误 HV000030: No validator could be found for constraint EnumChecker validating type MyEnum Check configuration for ‘myenum’

使用此 class 上的注释进行验证,我无法做到 private final String myenum 因为我需要将其用作枚举才能使用枚举中的函数

public class Request {
     @EnumChecker(enumclass = MyEnum.class)
     private final MyEnum myenum;
}

注释

@Documented
@Constraint(validatedBy = MyEnumValidator.class)
@Target({FIELD, PARAMETER, TYPE, TYPE_USE, TYPE_PARAMETER, METHOD, CONSTRUCTOR, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface EnumChecker {
  String message() default "must be one of these values";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
  Class<? extends Enum> enumClass();
}

验证者

public class MyEnumValidator implements ConstraintValidator<EnumChecker, String> {
  private List<String> validEnumList;

  @Override
  public void initialize(EnumChecker constraintAnnotation) {
    validEnumList = Arrays.stream(constraintAnnotation.enumClass().getEnumConstants())
        .map(Enum::name)
        .collect(Collectors.toList());
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    return validEnumList.contains(value);
  }
}

枚举

public enum MyEnum {

  YES, NO;

  private static final Map<MyEnum, String> MyEnumConverter =
      Map.of(YES, "yes");

  public String toMyString() {
    return MyEnumConverter.get(this);
  }

}

首先删除 myenum 中的 final 修饰符并为该字段创建 setter 和 getter,因为 Jackson 无法绑定来自 http 的值例如向您的 Request class 请求。

public class Request {
  @EnumChecker(enumClass = MyEnum.class)
  private MyEnum myenum;
  
  public MyEnum getMyenum() {
    return myenum;
  }
  
  public void setMyenum(MyEnum myenum) {
    this.myenum = myenum;
  }
}

然后更改 ConstraintValidator 目标类型以匹配 MyEnum 而不是 String

public class MyEnumValidator implements ConstraintValidator<EnumChecker, MyEnum> {

  private List<MyEnum> validEnumList;

  @Override
  public void initialize(EnumChecker constraintAnnotation) {
    validEnumList = Arrays.stream(constraintAnnotation.enumClass().getEnumConstants())
        .collect(Collectors.toList());
  }
  @Override
  public boolean isValid(MyEnum value, ConstraintValidatorContext context) {
    return validEnumList.contains(value);
  }
}

测试:我做了以下测试

@RestController
public class MainController {

  @PostMapping("/annot")
  public String filter(@RequestBody @Valid Request req) {
    return req.getMyenum().name();
  }
}

我还更改了 MyEnumValidator 的实现以仅查看验证效果并证明它发生了。 (我承认目前这个验证器没有意义。同样使用 only @RequestBody 保证 myenum can only Have YES or NO 值否则抛出异常)

public class MyEnumValidator implements ConstraintValidator<EnumChecker, MyEnum> {

  private List<MyEnum> validEnumList;

  @Override
  public void initialize(EnumChecker constraintAnnotation) {
    validEnumList = Arrays.stream(constraintAnnotation.enumClass().getEnumConstants())
        .collect(Collectors.toList());
  }
  @Override
  public boolean isValid(MyEnum value, ConstraintValidatorContext context) {
    return validEnumList.contains(value) && value.name().length() == 3;
  }
}

无效案例:

堆栈跟踪:

Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String api.sweater.controller.MainController.filter(api.sweater.request.Request): [Field error in object 'request' on field 'myenum': rejected value [NO]; codes [EnumChecker.request.myenum,EnumChecker.myenum,EnumChecker.api.sweater.request.MyEnum,EnumChecker]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [request.myenum,myenum]; arguments []; default message [myenum],class api.sweater.request.MyEnum]; default message [must be one of these values]] ]