2011-01-16 9 views
19

Esiste un modo per verificare in modo dichiarativo se un enum ha un valore specificato. Per esempio:JSF 2: utilizzo delle enumerazioni nell'attributo di rendering

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status == Status.ERROR}" /> 

E 'un po' noioso per definire un metodo nel beand gestito che controlla questo per ogni valore enum, per esempio

public boolean isStateIsError() { 
    return current.getStatus() == Status.ERROR; 
} 

C'è un modo più breve/migliore per farlo?

risposta

34

Until EL 3.0 non è possibile importare enumerazioni in ambito EL. Puoi comunque trattarli e confrontarli come stringhe, ad esempio il valore della costante enum deve essere quotato come di seguito.

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status eq 'ERROR'}" /> 
+0

stringa viene valutata come chiamare metodo Equals() o un confronto omogeneo con riferimento? – user3663882

7

So che questa domanda è un po 'più vecchio, ma ho avuto lo stesso problema e ha trovato un'altra soluzione, che voglio condividere:

Creare una personalizzata EL-Resolver e uso enumerazioni e Java costanti come oggetti in JSF el:

<h:graphicImage name="error.png" library="images" 
     rendered="#{viewController.current.status == Status.ERROR}" /> 

Ma prima di poter utilizzare enumerazioni questo modo si ha a che fare 3 passi.

1. passo - Copia questa classe e sostituire "MY_ENUM" attraverso il vostro enumClass (nell'esempio di cui sopra sarebbe "Stato")

public class EnumCache { 
    private Map<String, Object> propertCache = new HashMap<String, Object>(); 
    private Map<String, Class> baseCache = new HashMap<String, Class>(); 
    private static EnumCache staticEnumCache = null; 

    public static EnumCache instance() { 
     if (staticEnumCache == null) { staticEnumCache = new EnumCache(); } 
     return staticEnumCache; 
    } 
    private EnumCache() { 
     List<Class<?>> classes = new ArrayList<Class<?>>(); 
     classes.add(MY_ENUM.class); 

     for(Class clazz : classes) { 
      try { 
       baseCache.put(clazz.getSimpleName(), clazz); 
       Method m = clazz.getMethod("values", (Class[]) null); 
       Enum<?>[] valueList = (Enum[]) m.invoke(null, (Object[]) null); 
       for (Enum<?> en : valueList) { 
        propertCache.put(clazz.getSimpleName() + "." + en.name(), en); 
       } 
      } catch (Exception e) { 
       System.err.println(clazz.getSimpleName(), e); 
      } 
     } 
    } 
    public Object getValueForKey(String key) { 
     return propertCache.get(key); 
    } 
    public Class getClassForKey(String key) { 
     return baseCache.get(key); 
    } 
} 

2. passo - aggiungere questo ENUMresolver - Questo classe sarà mappare la tua espressione JSF alla enum nella cache (fase 1)

public class MyEnumResolver extends ELResolver { 

    public Object getValue(ELContext context, Object base, Object property) { 
     Object result = null; 
     if (base == null) { 
      result = EnumCache.instance().getClassForKey(property + ""); 
     } else if (base instanceof Class) { 
      result = EnumCache.instance().getValueForKey(((Class) base).getSimpleName() + "." + property); 
     } 
     if (result != null) { 
      context.setPropertyResolved(true); 
     } 
     return result; 
    } 

    public Class<?> getCommonPropertyType(ELContext context, Object base) { 
     return null; 
    } 
    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) { 
     return null; 
    } 
    public Class<?> getType(ELContext context, Object base, Object property) { 
     return null; 
    } 
    public boolean isReadOnly(ELContext context, Object base, Object property) { 
     return false; 
    } 
    public void setValue(ELContext context, Object base, Object property, Object arg3) { 
    } 
} 

3. passo - registrare l'ENUMresolver in faces-config.xml

<faces-config> 
    <application> 
     <el-resolver>com.asd.MyEnumResolver</el-resolver> 
    </application> 
</faces-config> 

NOTA: Se si vuole accedere ai costanti Java in questo modo, devi solo di estendere il costruttore della classe enumCache. Questo (untestet) esempio dovrebbe funzionare:

baseCache.put(CLASS_WITH_CONSTANTS.getSimpleName(), clazz); 
for (Field field : CLASS_WITH_CONSTANTS.getDeclaredFields()) { 
    try { 
     propertCache.put(CLASS_WITH_CONSTANTS.getSimpleName() + "." 
        + field.getName(), field.get(null)); 
    } catch (Exception e) { } 
} 

Spero che questo codice ridotto, ma di lavoro può aiutare qualcuno.


Aggiornamento

vedo questo vantaggi:

  1. Se si utilizza stringhe in JSF (viewController.current.status == 'ERROR_abcdefg'), è possibile misspell il valore e non lo riconoscerò così in fretta. Con la mia soluzione si otterrebbe un errore durante il caricamento del file jsf, perché l'enum non può essere risolto.

  2. È possibile visualizzare nel codice sorgente che "ERRORE" è il valore dell'enum "STATO".

  3. Quando si confrontano due valori in el, verrà confrontata anche la classe dell'enumerazione. Quindi, ad esempio, PersonState.ACTIV non è lo stesso di AccounState.ACTIV.

  4. Quando devo modificare il mio valore enum da PersonState.ACTIV a PersonState.ACTIVATED posso cercare la stringa "PersonState.ACTIV" nel mio codice sorgente. cercare "ACTIV" avrebbe molte più corrispondenze.

+5

Quali vantaggi offre esattamente questo approccio? In Java, il vantaggio principale dell'utilizzo di riferimenti enumerati diretti è stato l'applicazione di valori di tempo di compilazione, ma questo vantaggio non esiste in EL, anche non con questo risolutore. – BalusC

+0

Questo è ancora più noioso della creazione di un metodo nel bean gestito! Comunque, è bello sapere che questo può essere fatto. –

1

ho risolto un problema simile statically scarico tutte le chiavi enum (che vengono utilizzati nei componenti UI resi) in una mappa e poi utilizzare un metodo statico getByKey per convertire il valore dall'interfaccia utente in un effettivo enum nativo nel setter, un'eccezione se il valore fornito è valido:

public enum ReportType { 

    FILING("F", "Filings"), 
    RESOLUTION("R", "Resolutions"), 
    BASIS("B", "Bases"), 
    STAFF("T", "Staff Counts"), 
    COUNTS("I", "Counts"); 

    private String key; 
    private String label; 

    private static Map<String, ReportType> keyMap = new HashMap<String, ReportType>(); 

    static { 
     for(ReportType type : ReportType.values()) { 
      keyMap.put(type.getKey(), type); 
     } 
    } 

    private ReportType(String _key, String _label) { 
     this.key = _key; 
     this.label = _label; 

    } 

    public String getKey() { 
     return this.key; 
    } 

    public String getLabel() { 
     return this.label; 
    } 

    public static List<ReportType> getValueList() { 
     return Arrays.asList(ReportType.values()); 
    } 

    public static ReportType getByKey(String _key) { 
     ReportType result = keyMap.get(_key); 

     if(result == null) { 
      throw new IllegalArgumentException("Invalid report type key: " + _key); 
     } 

     return result; 
    } 
} 

nella strato di interfaccia, la chiave enum viene utilizzato come valore e l'etichetta enum viene utilizzato come etichetta:

<f:selectItems var="rptTypeItem" value="#{reportController.allReportTypes}" 
    itemLabel="#{rptTypeItem.label}" itemValue="#{rptTypeItem.key}"/> 

Nel managed bean, ho convertire l'enumerazione in un elenco renderable, utilizzando il getValueList() da enum:

public List<ReportType> getAllReportTypes() { 
    return ReportType.getValueList(); 
} 

Infine, il [g | s] Etters nel look bean gestito nel modo seguente:

public String getReportType() { 
    return this.crtRptType.getKey(); 
} 

public void setReportType(String _val) { 
    this.crtRptType = ReportType.getByKey(_val); 
} 
1

penso che potrebbe essere fatto è la seguente modo:

Creare un metodo in voi di fagioli che sarebbe tornato l'elenco delle enumerazioni, per esempio

public Status[] getStatuses() { 
    Status.values(); 
} 

quindi è possibile utilizzare l'enum in EL come questo

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status == someBean.statuses[0]}" /> 

partendo dal presupposto che l'ordine dei membri enum non sta per essere modificato (ad es. qui statuses [0] è ERRORE). Tuttavia, vorrei correggere le posizioni di questo tipo:

public Status[] getStatuses() { 
    Status myStatuses = new Status [2]; // or whatever number of statuses you are going to use in UI 
    myStatuses [0] = Status.ERROR; 
    myStatuses [1] = Status.RUNNING; 
    return myStatuses; 
} 

Questo non è ancora soluzione dinamica, ma è meglio di hard-codifica in EL. Potrebbe essere particolarmente utile quando si utilizza la localizzazione per i propri stati (valori enum in base alla locale/traduzione).

-1

ho risolvere un problema simile con: Confronto

<p:graphicImage name="images/close.png" rendered="#{i.unityEnum.name().equals('DAY')}" /> 
Problemi correlati