Java 如何在枚举中使用 Hibernate 验证注释?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18205787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Hibernate validation annotations with enums?
提问by membersound
How can I use hibernate annotations to validate an enum member field? The following does not work:
如何使用休眠注释来验证枚举成员字段?以下不起作用:
enum UserRole {
USER, ADMIN;
}
class User {
@NotBlank //HV000030: No validator could be found for type: UserRole.
UserRole userRole;
}
采纳答案by Sebastien Lorber
Note you can also create a validator to check a String is part of an enumeration.
请注意,您还可以创建一个验证器来检查字符串是否是枚举的一部分。
public enum UserType { PERSON, COMPANY }
@NotNull
@StringEnumeration(enumClass = UserCivility.class)
private String title;
@Documented
@Constraint(validatedBy = StringEnumerationValidator.class)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, PARAMETER, CONSTRUCTOR })
@Retention(RUNTIME)
public @interface StringEnumeration {
String message() default "{com.xxx.bean.validation.constraints.StringEnumeration.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
}
public class StringEnumerationValidator implements ConstraintValidator<StringEnumeration, String> {
private Set<String> AVAILABLE_ENUM_NAMES;
@Override
public void initialize(StringEnumeration stringEnumeration) {
Class<? extends Enum<?>> enumSelected = stringEnumeration.enumClass();
//Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
Set<? extends Enum<?>> enumInstances = Sets.newHashSet(enumSelected.getEnumConstants());
AVAILABLE_ENUM_NAMES = FluentIterable
.from(enumInstances)
.transform(PrimitiveGuavaFunctions.ENUM_TO_NAME)
.toSet();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null ) {
return true;
} else {
return AVAILABLE_ENUM_NAMES.contains(value);
}
}
}
This is nice because you don't loose the information of the "wrong value". You can get a message like
这很好,因为您不会丢失“错误值”的信息。您可以收到类似的消息
The value "someBadUserType" is not a valid UserType. Valid UserType values are: PERSON, COMPANY
值“someBadUserType”不是有效的用户类型。有效的 UserType 值为:PERSON、COMPANY
Edit
编辑
For those who want a non-Guava version it should work with something like:
对于那些想要非 Guava 版本的人来说,它应该适用于以下内容:
public class StringEnumerationValidator implements ConstraintValidator<StringEnumeration, String> {
private Set<String> AVAILABLE_ENUM_NAMES;
public static Set<String> getNamesSet(Class<? extends Enum<?>> e) {
Enum<?>[] enums = e.getEnumConstants();
String[] names = new String[enums.length];
for (int i = 0; i < enums.length; i++) {
names[i] = enums[i].name();
}
Set<String> mySet = new HashSet<String>(Arrays.asList(names));
return mySet;
}
@Override
public void initialize(StringEnumeration stringEnumeration) {
Class<? extends Enum<?>> enumSelected = stringEnumeration.enumClass();
AVAILABLE_ENUM_NAMES = getNamesSet(enumSelected);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null ) {
return true;
} else {
return AVAILABLE_ENUM_NAMES.contains(value);
}
}
}
And to customize the error message and display the appropriate values, check this: https://stackoverflow.com/a/19833921/82609
要自定义错误消息并显示适当的值,请检查:https: //stackoverflow.com/a/19833921/82609
回答by Suresh Atta
Validate that the annotated string is not null or empty. The difference to NotEmpty is that trailing whitespaces are getting ignored.
验证带注释的字符串不为 null 或为空。NotEmpty 的不同之处在于尾随空格被忽略。
Where as UserRole
is not String and an object
Use @NotNull
asUserRole
不是 String 和object
Use@NotNull
The annotated element must not be null. Accepts any type.
带注释的元素不能为空。接受任何类型。
回答by Raf
I suppose a more closely related to Sebastien's answerabove with fewer lines of code and makes use of EnumSet.allOf
in the expense of a rawtypes
warning
我认为与上面塞巴斯蒂安的答案更密切相关,代码行更少,并且EnumSet.allOf
以rawtypes
警告为代价使用
Enums setup
枚举设置
public enum FuelTypeEnum {DIESEL, PETROL, ELECTRIC, HYBRID, ...};
public enum BodyTypeEnum {VAN, COUPE, MUV, JEEP, ...};
Annotation setup
注释设置
@Target(ElementType.FIELD) //METHOD, CONSTRUCTOR, etc.
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.class)
public @interface ValidateEnum {
String message() default "{com.xxx.yyy.ValidateEnum.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> targetClassType();
}
Validator setup
验证器设置
public class EnumValidator implements ConstraintValidator<ValidateEnum, String> {
private Set<String> allowedValues;
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void initialize(ValidateEnum targetEnum) {
Class<? extends Enum> enumSelected = targetEnum.targetClassType();
allowedValues = (Set<String>) EnumSet.allOf(enumSelected).stream().map(e -> ((Enum<? extends Enum<?>>) e).name())
.collect(Collectors.toSet());
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value == null || allowedValues.contains(value)? true : false;
}
}
Now go ahead and annotate your fields as follow
现在继续注释您的字段如下
@ValidateEnum(targetClassType = FuelTypeEnum.class, message = "Please select ...."
private String fuelType;
@ValidateEnum(targetClassType = BodyTypeEnum.class, message = "Please select ...."
private String bodyType;
The above assumes you have the Hibernate Validator
setup and working with default annotation.
以上假设您已Hibernate Validator
设置并使用默认注释。
回答by Abhijit Sarkar
Often times, attempting to convert to an enum is not just by name (which is the default behavior with valueOf
method). For example, what if you have enums representing DayOfWeek
and you want an integer to be converted to a DayOfWeek
? To do that, I created the following annotation:
很多时候,尝试转换为枚举不仅仅是通过名称(这是valueOf
方法的默认行为)。例如,如果您有枚举表示DayOfWeek
并且希望将整数转换为DayOfWeek
? 为此,我创建了以下注释:
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = {ValidEnumValueValidator.class})
public @interface ValidEnumValue {
String message() default "invalidParam";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> value();
String enumMethod() default "name";
String stringMethod() default "toString";
}
public class ValidEnumValueValidator implements ConstraintValidator<ValidEnumValue, String> {
Class<? extends Enum<?>> enumClass;
String enumMethod;
String stringMethod;
@Override
public void initialize(ValidEnumValue annotation) {
this.enumClass = annotation.value();
this.enumMethod = annotation.enumMethod();
this.stringMethod = annotation.stringMethod();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
Enum<?>[] enums = enumClass.getEnumConstants();
Method method = ReflectionUtils.findMethod(enumClass, enumMethod);
return Objects.nonNull(enums) && Arrays.stream(enums)
.map(en -> ReflectionUtils.invokeMethod(method, en))
.anyMatch(en -> {
Method m = ReflectionUtils.findMethod(String.class, stringMethod);
Object o = ReflectionUtils.invokeMethod(m, value);
return Objects.equals(o, en);
});
}
}
You'd use it as follows:
您可以按如下方式使用它:
public enum TestEnum {
A("test");
TestEnum(String s) {
this.val = s;
}
private String val;
public String getValue() {
return this.val;
}
}
public static class Testee {
@ValidEnumValue(value = TestEnum.class, enumMethod = "getValue", stringMethod = "toLowerCase")
private String testEnum;
}
Above implementation uses ReflectionUtilsfrom Spring framework and Java 8+.
以上实现使用来自 Spring 框架和 Java 8+ 的ReflectionUtils。