Accéder à la valeur Enum en utilisant EL avec JSTL

104

J'ai un Enum appelé Status défini comme tel:

public enum Status { 

    VALID("valid"), OLD("old");

    private final String val;

    Status(String val) {
        this.val = val;
    }

    public String getStatus() {
        return val;
    }

}

Je voudrais accéder à la valeur de à VALIDpartir d'une balise JSTL. Plus précisément l' testattribut de la <c:when>balise. Par exemple

<c:when test="${dp.status eq Status.VALID">

Je ne sais pas si cela est possible.

IaCoder
la source

Réponses:

112

Une simple comparaison avec une chaîne fonctionne:

<c:when test="${someModel.status == 'OLD'}">
Alexandre Vasiljev
la source
11
Pour ceux qui ont besoin d'une source: Ceci est spécifié (par exemple) dans la section 1.17 de la "Spécification du langage d'expression, version 2.2", qui fait partie de JSR-245 .
meriton
4
La spécification JavaServer Pages ™, version 2.0 dit dans JSP.2.3.5.7: "• Si A ou B est String contraindre A et B à String, comparez lexicalement"
Roland Illig
11
Mais vous perdez l'avantage d'avoir une énumération: cela pourrait conduire à des malentendus encombrants si l'énumération est modifiée un jour. Habituellement, si je me surprends à changer une énumération, je me sens assez en sécurité, et je ne me souviendrais probablement pas de cette référence chaîne à énumération dans cette vue ...
reallynice
1
Est-ce une comparaison avec la toString de l'énumération? Donc, si vous remplacez la toString (par exemple, vous voulez un nom d'affichage convivial), vous devez vous assurer que vous modifiez également la valeur qui est comparée.
Rupert Madden-Abbott
1
FWIW, aujourd'hui sur mon Java 8 (IBM Java pour WebSphere, au cas où cela importerait), cela ne semble pas fonctionner. Cela semble ne fonctionner que si on compare avec la valeur de la chaîne, qui serait ici en minuscules "old"
dbreaux
54

Si vous utilisez Spring MVC, le langage d'expression Spring (SpEL) peut être utile:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
la source
1
Cela semble ne pas fonctionner pour les énumérations internes? Causé par: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): Type introuvable 'my.package.model.EngagementRequest.EngagementStatus'
Eddie
4
Essayez d'utiliser 'my.package.model.EngagementRequest $ EngagementStatus'
James
Une bonne chose à propos de cette solution est que vous obtenez un message d'erreur s'il y a une erreur dans votre expression, ce qui ne se produit pas toujours avec <c:if>et <c:when>(ils échouent silencieusement).
vegemite4me
41

Vous avez 3 choix ici, dont aucun n'est parfait:

  1. Vous pouvez utiliser un scriptlet dans l' testattribut:

    <c:when test="<%= dp.getStatus() == Status.VALID %>">

    Cela utilise l'énumération, mais il utilise également un scriptlet, ce qui n'est pas la "bonne manière" dans JSP 2.0. Mais surtout, cela ne fonctionne pas lorsque vous souhaitez ajouter une autre condition à la même whenutilisation ${}. Et cela signifie que toutes les variables que vous souhaitez tester doivent être déclarées dans un scriptlet, ou conservées en requête, ou en session (la pageContextvariable n'est pas disponible dans les .tagfichiers).

  2. Vous pouvez comparer avec une chaîne:

    <c:when test="${dp.status == 'VALID'}">

    Cela semble propre, mais vous introduisez une chaîne qui duplique la valeur d'énumération et ne peut pas être validée par le compilateur. Donc, si vous supprimez cette valeur de l'énumération ou la renommez, vous ne verrez plus que cette partie du code n'est plus accessible. Vous devez essentiellement effectuer une recherche / remplacement dans le code à chaque fois.

  3. Vous pouvez ajouter chacune des valeurs d'énumération que vous utilisez dans le contexte de la page:

    <c:set var="VALID" value="<%=Status.VALID%>"/>

    et ensuite vous pouvez faire ceci:

    <c:when test="${dp.status == VALID}">

Je préfère la dernière option (3), même si elle utilise également un scriptlet. C'est parce qu'il ne l'utilise que lorsque vous définissez la valeur. Plus tard, vous pourrez l'utiliser dans des expressions EL plus complexes, avec d'autres conditions EL. Dans l'option (1), vous ne pouvez pas utiliser un scriptlet et une expression EL dans l' testattribut d'une seule whenbalise.

Mat
la source
1
En ce qui concerne l'option 2, le compilateur ne peut pas la vérifier, mais au moment de l'exécution, la chaîne sera convertie en une énumération en utilisant Enum.valueOf(Class<T> enumType, String name)ce qui déclenchera un ELExceptionsi l'énumération n'a pas de constante avec ce nom. L'expression ne sera pas toujours toujours fausse.
Redémarrage le
23

Donc, pour résoudre complètement mon problème, je devais faire ce qui suit:

<% pageContext.setAttribute("old", Status.OLD); %>

Ensuite, j'ai pu faire:

<c:when test="${someModel.status == old}"/>...</c:when>

qui a fonctionné comme prévu.

IaCoder
la source
12
utiliser des scriptlets est un mauvais style.
Eugene Retunsky
13

Voici deux autres possibilités:

Constantes JSP EL 3.0

Tant que vous utilisez au moins la version 3.0 d'EL, vous pouvez importer des constantes dans votre page comme suit:

<%@ page import="org.example.Status" %>
<c:when test="${dp.status eq Status.VALID}">

Cependant, certains IDE ne comprennent pas encore cela (par exemple IntelliJ ) donc vous n'obtiendrez aucun avertissement si vous faites une faute de frappe, jusqu'à l'exécution.

Ce serait ma méthode préférée une fois qu'il aura un support IDE approprié.

Méthodes d'assistance

Vous pouvez simplement ajouter des getters à votre énumération.

public enum Status { 
  VALID("valid"), OLD("old");

  private final String val;

  Status(String val) {
    this.val = val;
  }

  public String getStatus() {
    return val;
  }

  public boolean isValid() {
    return this == VALID;
  }

  public boolean isOld() {
    return this == OLD;
  }
}

Puis dans votre JSP:

<c:when test="${dp.status.valid}">

Ceci est pris en charge dans tous les IDE et fonctionnera également si vous ne pouvez pas encore utiliser EL 3.0. C'est ce que je fais pour le moment car cela garde toute la logique dans mon énumération.

Faites également attention s'il est possible que la variable stockant l'énumération soit nulle. Vous devrez d'abord vérifier cela si votre code ne garantit pas qu'il n'est pas nul:

<c:when test="${not empty db.status and dp.status.valid}">

Je pense que cette méthode est supérieure à celles où vous définissez une valeur intermédiaire dans le JSP car vous devez le faire sur chaque page où vous devez utiliser l'énumération. Cependant, avec cette solution, vous ne devez déclarer le getter qu'une seule fois.

Rupert Madden-Abbott
la source
2
La partie «Constantes JSP EL 3.0» doit être la réponse acceptée car c'est le moyen standard d'obtenir le résultat requis en utilisant la fonctionnalité intégrée. Sur une note latérale, InteliJ IDEA (au moins la version Ultimate 2017.2.4) le prend en charge hors de la boîte et affiche la liste des constantes disponibles lorsque vous tapez ${MyEnum.}, placez le curseur juste après le point et appuyez sur Ctrl+Spacepour afficher des suggestions.
izogfif
[ MISE À JOUR ] Il semble qu'IntelliJ IDEA a déjà résolu le problème mentionné dans cette réponse.
informatik01 du
10

À cette fin, je fais ce qui suit:

<c:set var="abc">
    <%=Status.OLD.getStatus()%>
</c:set>

<c:if test="${someVariable == abc}">
    ....
</c:if>

C'est moche, mais ça marche!

Motard Xtreme
la source
3

Je n'ai pas de réponse à la question de Kornel, mais j'ai une remarque sur les autres exemples de script. La plupart des expressions font implicitement confiance à la toString(), mais Enum.valueOf()attend une valeur qui provient de / correspond à la Enum.name()propriété. On devrait donc utiliser par exemple:

<% pageContext.setAttribute("Status_OLD", Status.OLD.name()); %>
...
<c:when test="${someModel.status == Status_OLD}"/>...</c:when>
Eremmel
la source
2

Ajoutez une méthode à l'énumération comme:

public String getString() {
    return this.name();
}

Par exemple

public enum MyEnum {
    VALUE_1,
    VALUE_2;
    public String getString() {
        return this.name();
    }
}

Ensuite, vous pouvez utiliser:

<c:if test="${myObject.myEnumProperty.string eq 'VALUE_2'}">...</c:if>
doyen
la source
1

Lors de l'utilisation d'un framework MVC, je mets ce qui suit dans mon contrôleur.

request.setAttribute(RequestParameterNamesEnum.INBOX_ACTION.name(), RequestParameterNamesEnum.INBOX_ACTION.name());

Cela me permet d'utiliser ce qui suit dans ma page JSP.

<script> var url = 'http://www.nowhere.com/?${INBOX_ACTION}=' + someValue;</script>

Il peut également être utilisé dans votre comparaison

<c:when test="${someModel.action == INBOX_ACTION}">

Ce que je préfère plutôt que de mettre une chaîne littérale.

ÉlectroniqueBlacksmith
la source
1
<%@ page import="com.example.Status" %>

1. ${dp.status eq Title.VALID.getStatus()}
2. ${dp.status eq Title.VALID}
3. ${dp.status eq Title.VALID.toString()}
  • Placez l'importation en haut , dans l'en-tête de page JSP
  • Si vous voulez travailler avec la méthode getStatus , utilisez # 1
  • Si vous voulez travailler avec l' élément enum lui-même, utilisez le # 2 ou le # 3
  • Vous pouvez utiliser == au lieu de eq
Mehdi
la source
-1

Je considère généralement que c'est une mauvaise pratique de mélanger du code java dans des fichiers jsps / tag. Utiliser 'eq' devrait faire l'affaire:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
la source
3
C'est donc une mauvaise pratique à utiliser à la ==place eq? Ils font tous les deux exactement la même chose, donc il n'y a aucun moyen de "tromper".
BalusC
Bien sûr, je ne faisais pas de déclaration concernant l'utilisation de eq vs ==. De nombreuses réponses à cette question impliquaient l'insertion de code java dans des fichiers jsp ou tag qui peuvent être une béquille. Je préfère garder la logique métier dans le code java (où elle peut être testée facilement et complètement) séparément de la logique d'affichage dans la JSP.
Eclatante
7
Pour moi, il semble tout aussi mauvais d'insérer des chaînes magiques dans votre JSP qui ne peuvent pas être vérifiées par le compilateur lorsque vous souhaitez refactoriser vos énumérations. On dirait qu'il n'y a pas de bonne solution à cela de chaque côté.
Lyle
-1

Je le fais de cette façon quand il y a beaucoup de points à utiliser ...

public enum Status { 

    VALID("valid"), OLD("old");

    private final String val;

    Status(String val) {
        this.val = val;
    }

    public String getStatus() {
        return val;
    }

    public static void setRequestAttributes(HttpServletRequest request) {
        Map<String,String> vals = new HashMap<String,String>();
        for (Status val : Status.values()) {
            vals.put(val.name(), val.value);
        }
        request.setAttribute("Status", vals);
    }

}

JSP

<%@ page import="...Status" %>
<% Status.setRequestAttributes(request) %>

<c:when test="${dp.status eq Status.VALID}">
...
HS Shin
la source
-2

Dans la classe Java:

    public class EnumTest{
    //Other property link
    private String name;
    ....

        public enum Status {
                ACTIVE,NEWLINK, BROADCASTED, PENDING, CLICKED, VERIFIED, AWARDED, INACTIVE, EXPIRED, DELETED_BY_ADMIN;
            }

        private Status statusobj ;

    //Getter and Setters
}

Alors maintenant, POJO et enum obj sont créés. Maintenant EnumTest vous allez définir dans l'objet de session en utilisant dans le servlet ou la classe de contrôleur session.setAttribute ("enumTest", EnumTest);

Dans la page JSP

<c:if test="${enumTest.statusobj == 'ACTIVE'}">

//TRUE??? THEN PROCESS SOME LOGIC
Pavan
la source