2013-03-12 4 views
10

मैं निम्नलिखित BeanValidation कोड है कि ठीक काम करता है, और परमिट मान्य करने के लिए है कि एक सेम के साथ एनोटेट है:जेनिक्स और कक्षा <? Enum <?>>, EnumSet.allOf (वर्ग) class.getEnumConstants बनाम() फैली हुई है

@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

संबंधित टिकट: http://stackoverflow.com/questions/5548091/problem-when-trying-to-use-generics –

+0

यह भी एक: http://stackoverflow.com/questions/3546745/multiple-wildcards-on- एक-सामान्य-मीटर ethods-makes-java-compiler-and-me-very-confu – assylias

+1

@ क्रिस्टोफ्रॉउसी: टिकट? StackOverflow अब एक समर्थन प्रणाली है :) – mellamokb

उत्तर

8

मेरा अनुमान है कि ? extends Enum<?> में दो ? भिन्न हो सकते हैं जबकि allOfT 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; } 
} 

ये लाइनें संकलन होगा:

उदाहरण के लिए, निम्नलिखित कोड पर विचार क्योंकि हम जानते हैं कि दो TenumValue.enumClass() में ही कर रहे हैं

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

लेकिन यह ऐसा नहीं करेंगे:

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

क्योंकि आपने जानकारी खो दी है एक मध्यवर्ती चरण के रूप में Class<? extends Enum<?>> का उपयोग करना।

+0

धन्यवाद, मुझे लगता है कि मेरे पास कोई विकल्प नहीं है क्योंकि मैं EnumValue <टी को एनम > –

3

@ assylias के समाधान के मेरे स्पष्टीकरण:

क्या हम वर्ग के प्रकार के बारे में व्यक्त करना चाहता हूँ कि यह एक

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

है, लेकिन जावा हमें में एक प्रकार चर 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) 

लागू करने के लिए वाइल्डकार्ड और वाइल्डकार्ड कब्जा दोहन कर सकते हैं लेकिन यह हमारे मामले में काम नहीं करेगा, क्योंकि Class<T> में 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() 
है
+0

+1 एनोटेशन के एनोट विशेषता को नहीं बना सकता है। अच्छा स्पष्टीकरण। मैं सोच रहा हूं कि 'EnumClass जंगली = नया EnumClass <> (enumClass); 'जावा 7 में काम करता है। –

संबंधित मुद्दे