我有以下BeanValidation代码可以正常工作,并允许验证带有注释的bean:
@EnumValue(enumClass = MyTestEnum.class)
private String field;
public enum MyTestEnum {
VAL1, VAL2;
}
仅当字段值为“VAL1”或“VAL2”时才会被验证。
public class EnumNameValidator implements ConstraintValidator<EnumValue, String> {
private Set<String> AVAILABLE_ENUM_NAMES;
@Override
public void initialize(EnumValue enumValue) {
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = Sets.newHashSet(enumSelected.getEnumConstants());
AVAILABLE_ENUM_NAMES = FluentIterable
.from(enumInstances)
.transform(PrimitiveGuavaFunctions.ENUM_TO_NAME)
.toImmutableSet();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null ) {
return true;
} else {
return AVAILABLE_ENUM_NAMES.contains(value);
}
}
}
我不明白为什么我的第一次尝试失败了。使用以下代码上方的enumSelected.getEnumConstants()
代替:
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
Intellij 12没有突出显示任何错误,但编译器说:
java: method allOf in class java.util.EnumSet<E> cannot be applied to given types;
required: java.lang.Class<E>
found: java.lang.Class<capture#1 of ? extends java.lang.Enum<?>>
reason: inferred type does not conform to declared bound(s)
inferred: capture#1 of ? extends java.lang.Enum<?>
bound(s): java.lang.Enum<capture#1 of ? extends java.lang.Enum<?>>
我不明白这个问题,而且我的代码也运行良好:
private static <T extends Enum<T> & EnumAlternativeName> T safeGetByAlternativeName(Class<T> enumClass, String alternativeName) {
for ( T t : EnumSet.allOf(enumClass) ) {
if ( t.getAlternativeName().equals(alternativeName) ) {
return t;
}
}
return null;
}
答案 0 :(得分:8)
我的猜测是,在? extends Enum<?>
中,?
两个allOf
可能不同,而T extends Enum<T>
期望T
两个static enum MyEnum {}
static class EnumValue<T extends Enum<T>> {
Class<T> enumClass;
EnumValue(Class<T> enumClass) {
this.enumClass = enumClass;
}
Class<T> enumClass() { return enumClass; }
}
相同。
例如,请考虑以下代码:
EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass());
这些行将编译:
T
因为我们知道enumValue.enumClass()
中的两个EnumValue enumValue = new EnumValue(MyEnum.class);
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
是相同的但不会:
Class<? extends Enum<?>>
因为您使用{{1}}作为中间步骤而丢失了信息。
答案 1 :(得分:3)
我对@ assylias的解决方案的解释:
我们想要表达的类型是它是
Class<E>, for some E, that E <: Enum<E>
但Java不允许我们在方法体中引入类型变量E
。
通常,我们可以利用通配符和通配符捕获来引入隐藏类型变量
class G<T extends b(T)> { ... } // b(T) is a type expression that may contain T
G<? extends A> --capture--> G<T>, for some T, that T <: A & b(T)
但是在我们的案例中,这不会起作用,因为T
中的Class<T>
没有使其有效的界限。
因此我们需要引入一个具有所需绑定
的新类型class EnumClass<E extends Enum<E>> // called EnumValue in assylias's solution
EnumClass(Class<E> enumClass)
Class<E> enumClass()
EnumClass<?> --capture--> EnumClass<E>, for some E, that E <: Enum<E>
然后我们致电EnumClass<E>.enumClass()
以产生
Class<E>, for some E, that E <: Enum<E>
这是我们一直努力实现的目标。
但是我们怎样才能调用EnumClass
的构造函数?问题的根源是我们没有enumClass
的正确类型,但EnumClass
的构造函数需要正确键入enumClass
。
Class<not-proper> enumClass = ...;
new EnumClass<...>(enumClass); // wont work
幸运的是(?)原始类型有助于禁用泛型类型检查
EnumClass raw = new EnumClass(enumClass); // no generics
EnumClass<?> wild = raw;
所以我们需要执行的最小体操才能将课程演绎到所需的类型
((EnumClass<?>)new EnumClass(enumClass)).enumClass()