2013-03-12 33 views
10

Tôi có đoạn code BeanValidation sau đó hoạt động tốt, và giấy phép để xác nhận rằng một bean chú thích với:Generics and Class <? mở rộng Enum <?>>, EnumSet.allOf (class) vs class.getEnumConstants()

@EnumValue(enumClass = MyTestEnum.class) 
    private String field; 

    public enum MyTestEnum { 
    VAL1, VAL2; 
    } 

sẽ được xác nhận chỉ nếu giá trị trường là "VAL1" hoặc "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); 
    } 
    } 

} 

Điều tôi không hiểu là tại sao nỗ lực đầu tiên của tôi không thành công. Sử dụng thay cho enumSelected.getEnumConstants() trên đoạn mã sau:

Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected); 

Intellij 12 không đánh dấu bất kỳ lỗi, nhưng trình biên dịch nói:

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<?>> 

Tôi không hiểu được vấn đề, và Tôi cũng có mã đó hoạt động tốt:

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

Vé liên quan: http://stackoverflow.com/questions/5548091/problem-when-trying-to-use-generics –

+0

Điều này cũng vậy: http://stackoverflow.com/questions/3546745/multiple-wildcards-on- a-generic-m ethods-make-java-compiler-and-me-very-confu – assylias

+1

@ChristopheRoussy: Vé? StackOverflow là một hệ thống hỗ trợ bây giờ :) – mellamokb

Trả lời

8

Tôi đoán là trong ? extends Enum<?> hai ? có thể khác nhau trong khi allOf mong đợi một T extends Enum<T> trong đó cả hai T đều giống nhau.

Ví dụ, hãy xem xét đoạn mã sau:

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; } 
} 

Những dòng này sẽ biên dịch:

EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor 
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass()); 

bởi vì chúng tôi biết rằng hai T trong enumValue.enumClass() đều giống nhau nhưng điều này sẽ không:

EnumValue enumValue = new EnumValue(MyEnum.class); 
Class<? extends Enum<?>> enumSelected = enumValue.enumClass(); 
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected); 

vì bạn đã mất thông tin sử dụng Class<? extends Enum<?>> làm bước trung gian.

+0

cảm ơn, tôi đoán tôi không có lựa chọn nào bởi vì tôi không thể làm cho thuộc tính enum đó của chú thích là EnumValue > –

3

lời giải thích của tôi về giải pháp @ assylias của:

gì chúng tôi muốn bày tỏ về loại của lớp là nó là một

Class<E>, for some E, that E <: Enum<E> 

nhưng Java không cho phép chúng tôi giới thiệu một loại biến E trong một thân phương pháp.

Thông thường, chúng ta có thể khai thác ký tự đại diện và ký tự đại diện chụp để giới thiệu một loại ẩn biến

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) 

Nhưng điều này sẽ không làm việc trong trường hợp của chúng tôi, kể từ khi T trong Class<T> không có một ràng buộc mà làm cho nó làm việc.

Vì vậy, chúng ta cần phải giới thiệu một loại mới với mong muốn ràng buộc

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> 

Sau đó chúng tôi gọi EnumClass<E>.enumClass() để mang lại một

Class<E>, for some E, that E <: Enum<E> 

đó là mục tiêu chúng tôi đã cố gắng để đạt được.

Nhưng làm cách nào chúng tôi có thể gọi hàm tạo của EnumClass? Nguồn gốc của vấn đề là chúng tôi không có loại thích hợp cho enumClass, nhưng hàm tạo của EnumClass muốn nhập đúng enumClass.

Class<not-proper> enumClass = ...; 
new EnumClass<...>(enumClass); // wont work 

May mắn thay (?) Loại thô giúp đây mà vô hiệu hóa Generics kiểm tra kiểu

EnumClass raw = new EnumClass(enumClass); // no generics 
EnumClass<?> wild = raw; 

Vì vậy, thể dục dụng cụ tối thiểu chúng ta cần phải thực hiện để cast lớp để loại mong muốn được

((EnumClass<?>)new EnumClass(enumClass)).enumClass() 
+0

+1 Giải thích tốt. Tôi tự hỏi nếu 'EnumClass wild = new EnumClass <> (enumClass);' hoạt động trong Java 7. –

Các vấn đề liên quan