Acesse o valor Enum usando EL com JSTL

104

Eu tenho um Enum chamado Status definido como:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Eu gostaria de acessar o valor de VALIDde uma tag JSTL. Especificamente, o testatributo da <c:when>tag. Por exemplo

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

Não tenho certeza se isso é possível.

IaCoder
fonte

Respostas:

112

Uma comparação simples com string funciona:

<c:when test="${someModel.status == 'OLD'}">
Alexander Vasiljev
fonte
11
Para aqueles que exigem uma fonte: Isso é especificado (por exemplo) na seção 1.17 da "Especificação de linguagem de expressão, versão 2.2", que faz parte do JSR-245 .
Meriton
4
A especificação JavaServer Pages ™, versão 2.0 diz em JSP.2.3.5.7: "• Se A ou B for String coagir A e B a String, compare lexicamente"
Roland Illig
11
Mas você perde a vantagem de ter um enum: isso pode levar a mal-entendidos complicados se o enum for alterado um dia. Normalmente, se eu me pegar alterando um enum, me sinto muito seguro e provavelmente não me lembraria daquela referência string-para-enum nessa visualização ...
realmente bom
1
Isso está comparando com o toString do enum? Portanto, se você substituir o toString (por exemplo, deseja um nome de exibição amigável), então você precisa ter certeza de alterar o valor que está sendo correspondido.
Rupert Madden-Abbott
1
FWIW, hoje no meu Java 8 (IBM Java para WebSphere, caso seja importante), isso não parece funcionar. Parece funcionar apenas se for comparado com o valor da string, que aqui seria minúsculo "antigo"
dbreaux
54

Se estiver usando Spring MVC, o Spring Expression Language (SpEL) pode ser útil:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
fonte
1
Parece que isso não funciona para enums internos? Causado por: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): O tipo não pode ser encontrado 'my.package.model.EngagementRequest.EngagementStatus'
Eddie
4
Tente usar 'my.package.model.EngagementRequest $ EngagementStatus'
James,
O bom dessa solução é que você receberá uma mensagem de erro se houver um erro em sua expressão, o que nem sempre acontece com <c:if>e <c:when>(eles falham silenciosamente).
vegemite4me
41

Você tem 3 opções aqui, nenhuma das quais é perfeita:

  1. Você pode usar um scriptlet no testatributo:

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

    Isso usa o enum, mas também usa um scriptlet, que não é o "jeito certo" no JSP 2.0. Mas o mais importante, isso não funciona quando você deseja adicionar outra condição ao mesmo whenusando ${}. E isso significa que todas as variáveis ​​que você deseja testar devem ser declaradas em um scriptlet ou mantidas em solicitação ou sessão (a pageContextvariável não está disponível nos .tagarquivos).

  2. Você pode comparar com string:

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

    Isso parece limpo, mas você está introduzindo uma string que duplica o valor enum e não pode ser validada pelo compilador. Portanto, se você remover esse valor do enum ou renomeá-lo, não verá que essa parte do código não está mais acessível. Basicamente, você tem que fazer uma busca / substituição por meio do código a cada vez.

  3. Você pode adicionar cada um dos valores enum que usar ao contexto da página:

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

    e então você pode fazer isso:

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

Prefiro a última opção (3), embora também use um scriptlet. Isso ocorre porque ele só o usa quando você define o valor. Mais tarde, você pode usá-lo em expressões EL mais complexas, junto com outras condições EL. Enquanto estiver na opção (1), você não pode usar um scriptlet e uma expressão EL no testatributo de uma única whentag.

Matt
fonte
1
Em relação à opção 2, o compilador não pode verificá-lo, mas em tempo de execução a string será convertida em um enum usando o Enum.valueOf(Class<T> enumType, String name)que irá disparar um ELExceptionse o enum não tiver uma constante com esse nome. A expressão nem sempre será falsa.
Reinicialize em
23

Portanto, para ter meu problema totalmente resolvido, eu precisava fazer o seguinte:

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

Então eu fui capaz de fazer:

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

que funcionou conforme o esperado.

IaCoder
fonte
12
usar scriptlets é um estilo ruim.
Eugene Retunsky de
13

Aqui estão mais duas possibilidades:

Constantes JSP EL 3.0

Contanto que você esteja usando pelo menos a versão 3.0 do EL, você pode importar constantes para sua página da seguinte maneira:

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

No entanto, alguns IDEs ainda não entendem isso (por exemplo, IntelliJ ), então você não receberá nenhum aviso se cometer um erro de digitação, até o tempo de execução.

Este seria o meu método preferido, uma vez que obtivesse o suporte IDE adequado.

Métodos auxiliares

Você pode simplesmente adicionar getters ao seu enum.

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

Então, em seu JSP:

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

Isso é compatível com todos os IDEs e também funcionará se você ainda não puder usar o EL 3.0. Isso é o que eu faço no momento porque mantém toda a lógica embrulhada em meu enum.

Também tome cuidado se for possível que a variável que armazena o enum seja nula. Você precisaria verificar isso primeiro se o seu código não garantir que não seja nulo:

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

Acho que esse método é superior àqueles em que você define um valor intermediário no JSP porque você tem que fazer isso em cada página em que precisa usar o enum. No entanto, com esta solução, você só precisa declarar o getter uma vez.

Rupert Madden-Abbott
fonte
2
A parte "JSP EL 3.0 Constants" deve ser a resposta aceita, pois é a maneira padrão de obter o resultado necessário usando a funcionalidade integrada. Em uma observação lateral, o InteliJ IDEA (pelo menos a versão Ultimate 2017.2.4) oferece suporte pronto para uso e mostra uma lista de constantes disponíveis quando você digita ${MyEnum.}, coloque um cursor logo após o ponto e pressione Ctrl+Spacepara mostrar sugestões.
izogfif
[ ATUALIZAÇÃO ] Parece que o IntelliJ IDEA já corrigiu o problema mencionado nesta resposta.
informatik01
10

Para este propósito, faço o seguinte:

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

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

Parece feio, mas funciona!

Xtreme Biker
fonte
3

Não tenho uma resposta para a pergunta de Kornel, mas tenho um comentário sobre os outros exemplos de script. A maior parte da expressão confia implicitamente no toString(), mas Enum.valueOf()espera um valor que vem / corresponde à Enum.name()propriedade. Portanto, deve-se usar, por exemplo:

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

Adicione um método ao enum como:

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

Por exemplo

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

Então você pode usar:

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

Ao usar um framework MVC, coloco o seguinte no meu controlador.

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

Isso me permite usar o seguinte em minha página JSP.

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

Também pode ser usado em sua comparação

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

O que eu prefiro colocar em um literal de string.

ElectronicBlacksmith
fonte
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()}
  • Coloque a importação no topo , no cabeçalho da página JSP
  • Se você quiser trabalhar com o método getStatus , use # 1
  • Se você quiser trabalhar com o próprio elemento enum , use um # 2 ou # 3
  • Você pode usar == em vez de eq
Mehdi
fonte
-1

Geralmente considero uma má prática misturar código java em arquivos jsps / tag. Usar 'eq' deve resolver o problema:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
fonte
3
Portanto, é uma má prática usar em ==vez de eq? Ambos fazem exatamente o mesmo, então não há como um "truque".
BalusC
Claro, eu não estava fazendo uma declaração sobre o uso de eq vs ==. Muitas respostas a essa pergunta envolveram a inserção de código java em arquivos jsp ou tag, o que pode ser uma muleta. Eu sou a favor de manter a lógica de negócios no código java (onde pode ser testado de forma simples e completa) separada da lógica de exibição no JSP.
Eclatante
7
Para mim, parece uma prática igualmente ruim inserir strings mágicas em seu JSP que não podem ser verificadas pelo compilador quando você deseja refatorar seus enums. Parece que não há uma boa solução para isso em nenhum dos lados.
Lyle
-1

Eu faço assim quando há muitos pontos para usar ...

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
fonte
-2

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

Portanto, agora POJO e enum obj são criados. Agora EnumTest você definirá no objeto de sessão usando na classe de servlet ou controlador session.setAttribute ("enumTest", EnumTest);

Na página JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Pavan
fonte