Bean Validation - 自定义注解实现枚举类型校验

定义枚举校验注解
/**
 * 枚举校验注解
 *
 * @author wangzefeng
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EnumValidator.class})
public @interface NotInEnum {

    String message() default "{javax.validation.constraints.NotInEnum.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * 校验的目标枚举类
     *
     * @return the Enum Class
     */
    @NotNull Class<? extends Enum<?>> enumClass();

    /**
     * 使用校验的模式
     *
     * @return the EnumValidMode
     * @see EnumValidMode
     */
    @NotNull EnumValidMode mode() default EnumValidMode.NAME;

    /**
     * <p>
     * 校验枚举的字段
     * 当 {@link NotInEnum#mode()} = {@link EnumValidMode#FIELD} 时起作用
     * 如果提供的字段不在目标枚举 {@link NotInEnum#enumClass()} 字段列表中,不校验
     * 如果待校验字段值为 null, 不校验,需要校验 not null 请配合 {@link NotNull} 使用
     * </p>
     *
     * @return fieldName
     * @see NotNull
     */
    String field() default "";
}
枚举校验模式
public enum EnumValidMode {
    /**
     * 枚举名称(即enum.name()/enum.toString())
     */
    NAME,

    /**
     * 枚举序号(enum.ordinal())
     */
    ORDINAL,

    /**
     * 枚举字段
     */
    FIELD;
}
配置 I18N 错误信息文案

配置 I18N 错误信息文案需要在 classpath 下配置 ValidationMessages_{code}.properties,可参考hibernate validator 提供的 ValidationMessages.properties。

Maven 项目在 resources 新建 Resource Bundle,Resource Bundle base name 为 ValidationMessages,按需添加 zh_CN(中文/中国)、en(英文)等等方言。在 ValidationMessages_{code}.properties 中添加具体的文案信息即可。如:

javax.validation.constraints.NotInEnum.message=枚举不在范围内
枚举校验器
public class EnumValidator implements ConstraintValidator<NotInEnum, Object> {

    private Class<? extends Enum<?>> enumClass;

    private Enum<?>[] enumConstants;

    private String fieldName;

    private EnumValidMode enumValidMode;


    @Override
    public void initialize(NotInEnum constraintAnnotation) {

        enumClass = constraintAnnotation.enumClass();

        enumConstants = enumClass.getEnumConstants();

        fieldName = constraintAnnotation.field();

        enumValidMode = constraintAnnotation.mode();
    }

    @SneakyThrows
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {

        if (value == null) {
            return true;
        }

        switch (enumValidMode) {
            case NAME:
                return useEnumName(value);
            case ORDINAL:
                return useOrdinal(value);
            case FIELD:
                return useField(value);
            default:
                return false;
        }
    }

    /**
     * 使用枚举的名称进行校验
     *
     * @param value the value
     * @return true / false
     */
    private boolean useEnumName(Object value) {
        for (Enum<?> constants : enumConstants) {
            if (constants.name().equals(value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 使用枚举的序号进行校验
     *
     * @param value the value
     * @return true / false
     */
    private boolean useOrdinal(Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Method method = enumClass.getMethod("ordinal");

        for (Enum<?> constants : enumConstants) {
            Object invoke = method.invoke(constants);
            if (invoke.equals(value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 使用枚举的字段进行校验
     *
     * @param value the value
     * @return true / false
     */
    private boolean useField(Object value) throws NoSuchFieldException, IllegalAccessException {
        Field[] fields = enumClass.getDeclaredFields();
        List<String> fieldNames = Stream.of(fields).map(Field::getName).collect(Collectors.toList());
        if (!fieldNames.contains(fieldName)) {
            return true;
        }

        Field field = enumClass.getDeclaredField(fieldName);
        field.setAccessible(true);

        for (Enum<?> constants : enumConstants) {
            Object fieldValue = field.get(constants);
            if (fieldValue.equals(value)) {
                return true;
            }
        }
        return false;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值