2011-12-28 13 views
5

Próbuję zrobić reverse lookup na kilka klas enum wykonawczych samą Field interfejs przez iteracja listy Class es użyciu Guava na Maps.uniqueIndex:Korzystanie rodzajowych z kolekcji klas enum realizacji tego samego interfejsu

Field valueOfSearchName = null; 
    for (final Class<? extends Enum<?>> clazz : ImmutableList.of(
     EntityField.class, 
     AddressField.class, 
     PersonFunctionType.class)) { 
    valueOfSearchName = Fields.valueOfSearchName(clazz, term.field()); // error 
    if (valueOfSearchName != null) { 
     // do something... 
     break; 
    } 
    } 

nie chcę powtarzać tego samego kodu (do tworzenia indeksu i robi odnośnika) we wszystkich klasach enum, więc używam pomocnika statyczną klasę Fields zawierający Fields.valueOfSearchName metody:

public static <E extends Enum<E> & Field> Field valueOfSearchName(
     final Class<E> clazz, final String searchName) { 
    // TODO: cache the index 
    final ImmutableMap<String, E> index = Maps.uniqueIndex(
     EnumSet.allOf(clazz), GET_SEARCH_NAME_FUNCTION); 
    return index.get(searchName); 
    } 

Niestety, Eclipse pokazuje błąd:

Bound mismatch: 
The generic method valueOfSearchName(Class<E>, String) of type Fields is not 
applicable for the arguments (Class<capture#1-of ? extends Enum<?>>, String). 
The inferred type capture#1-of ? extends Enum<?> is not a valid substitute 
for the bounded parameter <E extends Enum<E> & Field> 

Problem polega Class<? extends Enum<?>> clazz w for-each pętli (nie pasujące pola), ale nie wiem, jak radzić sobie z tego sprawy (oczywiście ja nie można dodać & Field do clazz).

+0

Ten link może być pomocny http://stackoverflow.com/questions/7032941/why-is-this-type-not-a-odpowiedni-substitute-for-the-type-parametr – kosa

+1

Eclipse słynie z niezgadzania się z zdrowy rozsądek. Sprawdź ten wpis: http://stackoverflow.com/questions/2220763/java-specific-enums-and-generic-enum-parameters –

+0

@baba Nie mogę zastąpić symbolu wieloznacznego '?' Nazwanym parametrem typu 'T' w pętli for-each, gdzie pojawia się problem ... Jednak [inspirowany przez Johna Skeeta odpowiedź na to pytanie] (http://stackoverflow.com/questions/5262096/how-do-i-get-the-value-of -an-enum-if-i-dont-know-the-class-at-compile-time) Zmieniłem pętlę na 'for (@SuppressWarnings (" rawtypes ") final Class clazz: ...' i to wystarczyło ...Czy to właściwa droga? – Xaerxess

Odpowiedz

0

Zainspirowany Tom Hawtin's answer utworzonego klasy otoki gospodarstwa Class ES, ale tylko te z podpisem <E extends Enum<E> & Field>:

public final static class FieldEnumWrapper<E extends Enum<E> & Field> { 
    private final Class<E> clazz; 
    private final ImmutableMap<String, E> index; 

    public static <E extends Enum<E> & Field> 
     FieldEnumWrapper<E> of(final Class<E> clazz) { 
    return new FieldEnumWrapper<E>(clazz); 
    } 

    private FieldEnumWrapper(final Class<E> clazz) { 
    this.clazz = clazz; 
    this.index = Maps.uniqueIndex(
     EnumSet.allOf(clazz), new Function<E, String>() { 
      @Override 
      public String apply(final E input) { 
      return input.searchName(); 
      } 
     }); 
    } 

    public Class<E> clazz() { 
    return clazz; 
    } 

    public Field valueOfSearchName(final String searchName) { 
    return index.get(searchName); 
    } 
} 

Teraz:

for (final FieldEnumWrapper<?> fieldEnum : ImmutableList.of(
    FieldEnumWrapper.of(EntityField.class), 
    FieldEnumWrapper.of(AddressField.class), 
    FieldEnumWrapper.of(PersonFunctionType.class))) { 
    valueOfSearchName = fieldEnum.valueOfSearchName("POD_I_OS_PARTNER"); 
    // ... 

jest typu bezpieczne i nieodpowiednie użycie statycznej fabryki FieldEnumWrapper „s

FieldEnumWrapper.of(NotEnumAndFieldClass.class) 

generuje błąd kompilacji.

Co więcej, valueOfSearchName jest teraz metodą FieldEnumWrapper, co ma więcej sensu w tej klasie pomocnika.

3

Rozważ Class<? extends List<?>. Class<? extends List<?> ma dwa symbole wieloznaczne, natomiast <E extends List<E>> Class<E> ma tylko parametr ogólny. Pierwsza z nich przyznaje Class<ArrayList<String>>. Więc bez robienia czegoś ekstra specjalnego dla wyliczeń, typy nie są kompatybilne.

Jak naprawić? Dodatkowa warstwa pośrednia!

public final class MetaEnum<E extends Enum<E>> { 
    private final E clazz; 
    public static <E extends Enum<E>> MetaEnum<E> of(E clazz) { 
     return clazz; 
    } 
    private MetaEnum(E clazz) { 
     this.clazz = clazz; 
    } 
    public E clazz() { 
     return clazz; 
    } 
    // ... 
} 

for (final MetaEnum<?> meta : ImmutableList.of(
    MetaEnum.of(EntityField  .class), 
    MetaEnum.of(AddressField  .class), 
    MetaEnum.of(PersonFunctionType.class) 
)) { 
    Field valueOfSearchName = Fields.valueOfSearchName(
     meta.clazz(), term.field() 
    ); 
    ... 

(Usual przepełnienie stosu dislaimer. Nie tak dużo, jak próbowali skompilować)

0

może coś takiego:

import java.util.*; 
class N { 
    static int n; 
} 
interface HasField { 
    int getField(); 
} 
enum Color implements HasField { 
    r, g, b; 
    public int getField() { 
     return field; 
    } 
    private int field = N.n++; 
} 
enum Day implements HasField { 
    m, t, w, th, f, sa, su; 
    public int getField() { 
     return field; 
    } 
    private int field = N.n++; 
} 
    class Helper { 
    Helper(Set<HasField> set) { 
     for (HasField hasField : set) 
      if (hasField instanceof Enum) { 
       Enum<?> e = (Enum<?>) hasField; 
       for (Object o : e.getDeclaringClass().getEnumConstants()) { 
        map.put(((HasField) o).getField(), (Enum<?>) o); 
       } 
      } else 
       throw new RuntimeException(hasField + " is not an enum!"); 
    } 
    final Map<Integer, Enum<?>> map = new TreeMap<Integer, Enum<?>>(); 
} 
public class Main { 
    public static void main(String[] args) { 
     Set<HasField> set = new LinkedHashSet<HasField>(); 
     set.add(Color.r); 
     set.add(Day.m); 
     Helper helper = new Helper(set); 
     for (int i = 0; i < N.n; i++) 
      System.out.println(i + " " + helper.map.get(i)); 
    } 
} 
+0

Tworzenie zestawu elementów intstead klas i kombinacji 'e.getDeclaringClass(). getEnumConstants()' wraz z 'Enum <-> rzutów HasField' nie jest czytelny i nie jest całkowicie bezpieczny ... A także' set.add (new HasField() {public int getField() {return 42;}}); 'jest klasą wykonawczą klasy ClassCastException. – Xaerxess

+0

dodano test: hasField instanceof Enum –

+0

Mimo to wolę czasy kompilacji raczej niż czas wykonywania;) – Xaerxess

Powiązane problemy