校验枚举类型
文章目录
- 1.介绍
- 2.校验枚举
- 3.校验枚举的类型
- 4.校验枚举的子集
- 5.验证字符串是否匹配枚举的值
1.介绍
使用自定义注解校验枚举类型
2.校验枚举
大多数标准注解都不支持枚举的校验。
例如
当将 @Pattern 注解应校验枚举时, Hibernate Validator会报以下错误:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint ‘javax.validation.constraints.Pattern’ validating type ‘com.niugang.javabase.enums.CustomerTypeEnum’. Check configuration for ‘customerTypeMatchesPattern’
实际上,可以应用于枚举的唯一标准注解是@NotNull 和@Null。
3.校验枚举的类型
准备
public enum CustomerTypeEnum {
/** * */
NEW,
OLD,
EDIT,
DEFAULT;
}
定义一个注解来校验枚举的类型:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class EnumNamePatternValidator implements ConstraintValidator<EnumNamePattern, Enum<?>> {
private Pattern pattern;
@Override
public void initialize(EnumNamePattern annotation) {
try {
pattern = Pattern.compile(annotation.regexp());
} catch (PatternSyntaxException e) {
throw new IllegalArgumentException("错误的正则", e);
}
}
@Override
public boolean isValid(Enum<?> value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
Matcher m = pattern.matcher(value.name());
return m.matches();
}
}
实现与标准的@Pattern 验证器非常相似。 但是,这一次,匹配了枚举的名称。
验证Bean
@Data
public class UserDto {
@NotNull(message = "姓名不能为空")
private String name;
@AssertTrue
private boolean working;
@Size(min = 10, max = 200, message
= "关于我在10到200字符")
private String aboutMe;
@Min(value = 18, message = "年龄最小18岁")
@Max(value = 150, message = "年龄最大150岁")
private int age;
@Email(message = "邮箱无效")
private String email;
@EnumNamePattern(regexp = "NEW|DEFAULT")
private CustomerTypeEnum customerType;
}
测试
UserDto user = new UserDto();
user.setName("张三");
user.setWorking(true);
user.setAboutMe("来自北京的张三,住在朝阳区");
user.setAge(50);
user.setCustomerType(CustomerTypeEnum.EDIT);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<UserDto>> violations = validator.validate(user);
for (ConstraintViolation<UserDto> violation : violations) {
System.out.println(violation);
}
ConstraintViolationImpl{interpolatedMessage=‘请匹配 “NEW|DEFAULT”’, propertyPath=customerType, rootBeanClass=class com.niugang.javabase.pojo.UserDto, messageTemplate=‘请匹配 “{regexp}”’}
4.校验枚举的子集
将枚举与正则表达式匹配不是类型安全的。 相反,与枚举的实际值进行比较更有意义。
但是,由于注解的限制,这样的注解不能通用。 这是因为注解的参数只能是特定枚举的具体值,而不是枚举父类的实例。
为 CustomerTypeEnum 枚举创建特定的子集校验注解:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = CustomerTypeSubSetValidator.class)
public @interface CustomerTypeSubset {
CustomerTypeEnum[] anyOf();
String message() default "必须为任何一个 {anyOf}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
@CustomerTypeSubset(anyOf = { CustomerTypeEnum.NEW, CustomerTypeEnum.OLD})
private CustomerTypeEnum customerType;
需要定义 CustomerTypeSubSetValidator 来检查给定枚举值的列表是否包含当前值:
public class CustomerTypeSubSetValidator implements ConstraintValidator<CustomerTypeSubset, CustomerTypeEnum> {
private CustomerTypeEnum[] subset;
@Override
public void initialize(CustomerTypeSubset constraint) {
this.subset = constraint.anyOf();
}
@Override
public boolean isValid(CustomerTypeEnum value, ConstraintValidatorContext context) {
return value == null || Arrays.asList(subset).contains(value);
}
}
5.验证字符串是否匹配枚举的值
创建一个注解来检查字符串对于特定枚举是否有效。
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ValueOfEnumValidator.class)
public @interface ValueOfEnum {
Class<? extends Enum<?>> enumClass();
String message() default "必须为 {enumClass},中的枚举值";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
校验逻辑
public class ValueOfEnumValidator implements ConstraintValidator<ValueOfEnum, CharSequence> {
private List<String> acceptedValues;
@Override
public void initialize(ValueOfEnum annotation) {
acceptedValues = Stream.of(annotation.enumClass().getEnumConstants())
.map(Enum::name)
.collect(Collectors.toList());
}
@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return acceptedValues.contains(value.toString());
}
}
@ValueOfEnum(enumClass = CustomerTypeEnum.class)
private String customerTypeString;
这种验证在处理 JSON 对象时特别有用。 因为出现了下面的异常,当把不正确的值从 JSON 对象映射到枚举时:
还没有评论,来说两句吧...