Acceda al valor de Enum usando EL con JSTL

104

Tengo un Enum llamado Estado definido como tal:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Me gustaría acceder al valor de VALIDdesde una etiqueta JSTL. Específicamente el testatributo de la <c:when>etiqueta. P.ej

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

No estoy seguro de si esto es posible.

IaCoder
fuente

Respuestas:

112

Una simple comparación con la cuerda funciona:

<c:when test="${someModel.status == 'OLD'}">
Alexander Vasiljev
fuente
11
Para aquellos que requieren una fuente: Esto se especifica (por ejemplo) en la sección 1.17 de la "Especificación del lenguaje de expresión, versión 2.2", que es parte de JSR-245 .
meriton
4
La especificación JavaServer Pages ™, versión 2.0 dice en JSP.2.3.5.7: "• Si A o B es String coacciona tanto A como B a String, compare léxicamente"
Roland Illig
11
Pero pierde la ventaja de tener una enumeración: esto podría provocar malentendidos engorrosos si la enumeración se cambia algún día. Por lo general, si me encuentro cambiando una enumeración, me siento bastante seguro, y probablemente no recordaría esa referencia de cadena a enumeración en esa vista ...
realmente agradable
1
¿Se compara esto con el toString de la enumeración? Por lo tanto, si anula toString (por ejemplo, desea un nombre de visualización amigable), debe asegurarse de cambiar también el valor con el que se compara.
Rupert Madden-Abbott
1
FWIW, hoy en mi Java 8 (IBM Java para WebSphere, en caso de que importe), esto no parece funcionar. Parece que solo funciona si se compara con el valor de la cadena, que aquí sería minúscula "antigua"
dbreaux
54

Si usa Spring MVC, Spring Expression Language (SpEL) puede ser útil:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
fuente
1
¿Parece que esto no funciona para enumeraciones internas? Causado por: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): No se puede encontrar el tipo 'my.package.model.EngagementRequest.EngagementStatus'
Eddie
4
Intente usar 'my.package.model.EngagementRequest $ EngagementStatus'
James
Lo bueno de esta solución es que recibe un mensaje de error si hay un error en su expresión, lo que no siempre ocurre con <c:if>y <c:when>(fallan silenciosamente).
vegemite4me
41

Tienes 3 opciones aquí, ninguna de las cuales es perfecta:

  1. Puede utilizar un scriptlet en el testatributo:

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

    Esto usa la enumeración, pero también usa un scriptlet, que no es la "forma correcta" en JSP 2.0. Pero lo más importante es que esto no funciona cuando desea agregar otra condición al mismo whenuso ${}. Y esto significa que todas las variables que desea probar deben declararse en un scriptlet, o mantenerse en una solicitud o sesión (la pageContextvariable no está disponible en los .tagarchivos).

  2. Puedes comparar con una cadena:

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

    Esto parece limpio, pero está introduciendo una cadena que duplica el valor de enumeración y no puede ser validado por el compilador. Entonces, si elimina ese valor de la enumeración o le cambia el nombre, no verá que esta parte del código ya no es accesible. Básicamente, debe realizar una búsqueda / reemplazo a través del código cada vez.

  3. Puede agregar cada uno de los valores de enumeración que usa en el contexto de la página:

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

    y luego puedes hacer esto:

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

Prefiero la última opción (3), aunque también usa un scriptlet. Esto se debe a que solo lo usa cuando establece el valor. Más adelante podrá utilizarlo en expresiones EL más complejas, junto con otras condiciones EL. Mientras esté en la opción (1), no puede usar un scriptlet y una expresión EL en el testatributo de una sola whenetiqueta.

Mate
fuente
1
Con respecto a la opción 2, el compilador no puede verificarla, pero en tiempo de ejecución la cadena se convertirá en una enumeración usando la Enum.valueOf(Class<T> enumType, String name)cual activará una ELExceptionsi la enumeración no tiene constante con ese nombre. La expresión no siempre será falsa.
Reinicio el
23

Entonces, para resolver mi problema por completo, necesitaba hacer lo siguiente:

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

Entonces pude hacer:

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

que funcionó como se esperaba.

IaCoder
fuente
12
usar scriptlets es de mal estilo.
Eugene Retunsky
13

Aquí hay dos posibilidades más:

Constantes JSP EL 3.0

Siempre que esté utilizando al menos la versión 3.0 de EL, puede importar constantes a su página de la siguiente manera:

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

Sin embargo, algunos IDE aún no comprenden esto (por ejemplo, IntelliJ ), por lo que no recibirá ninguna advertencia si comete un error tipográfico, hasta el tiempo de ejecución.

Este sería mi método preferido una vez que obtenga el soporte IDE adecuado.

Métodos auxiliares

Simplemente podría agregar captadores a su enumeración.

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

Luego, en tu JSP:

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

Esto es compatible con todos los IDE y también funcionará si aún no puede usar EL 3.0. Esto es lo que hago en este momento porque mantiene toda la lógica envuelta en mi enumeración.

También tenga cuidado si es posible que la variable que almacena la enumeración sea nula. Debería verificar eso primero si su código no garantiza que no sea nulo:

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

Creo que este método es superior a aquellos en los que estableces un valor intermedio en la JSP porque tienes que hacerlo en cada página donde necesitas usar la enumeración. Sin embargo, con esta solución, solo necesita declarar el getter una vez.

Rupert Madden-Abbott
fuente
2
La parte "JSP EL 3.0 Constants" debe ser la respuesta aceptada, ya que es la forma estándar de lograr el resultado requerido utilizando la funcionalidad incorporada. En una nota al margen, InteliJ IDEA (al menos la versión Ultimate 2017.2.4) lo admite desde el primer momento y muestra una lista de constantes disponibles cuando escribe ${MyEnum.}, coloque el cursor justo después del punto y presione Ctrl+Spacepara mostrar sugerencias.
izogfif
[ ACTUALIZACIÓN ] Parece que IntelliJ IDEA ya solucionó el problema mencionado en esta respuesta.
informatik01
10

Para ello hago lo siguiente:

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

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

Se ve feo, ¡pero funciona!

Motociclista xtreme
fuente
3

No tengo una respuesta a la pregunta de Kornel, pero tengo un comentario sobre los otros ejemplos de secuencias de comandos. La mayor parte de la expresión confía implícitamente en toString(), pero Enum.valueOf()espera un valor que proviene de / coincide con la Enum.name()propiedad. Entonces uno debería usar, por ejemplo:

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

Agregue un método a la enumeración como:

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

Por ejemplo

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

Entonces puedes usar:

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

Cuando uso un marco MVC, pongo lo siguiente en mi controlador.

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

Esto me permite usar lo siguiente en mi página JSP.

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

También se puede utilizar en su comparación

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

Lo que prefiero a poner una cadena literal.

Herrero Electrónico
fuente
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 la importación en la parte superior , en el encabezado de la página JSP
  • Si desea trabajar con el método getStatus , use el n . ° 1
  • Si desea trabajar con el elemento enum en sí, use # 2 o # 3
  • Puede usar == en lugar de eq
Mehdi
fuente
-1

En general, considero una mala práctica mezclar código Java en archivos jsps / tag. Usar 'eq' debería hacer el truco:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
fuente
3
Entonces, ¿es una mala práctica usar en ==lugar de eq? Ambos hacen exactamente lo mismo, por lo que no hay forma de "truco".
BalusC
Por supuesto, no estaba haciendo una declaración sobre el uso de eq vs ==. Muchas respuestas a esta pregunta implicaron insertar código java en archivos jsp o de etiquetas, lo que puede ser una muleta. Estoy a favor de mantener la lógica empresarial en código Java (donde se puede probar unitariamente de forma sencilla y completa) separada de la lógica de visualización en JSP.
Eclatante
7
A mí me parece una práctica igualmente mala insertar cadenas mágicas en su JSP que el compilador no puede verificar cuando desea refactorizar sus enumeraciones. Parece que no hay una buena solución para esto de ninguna de las partes.
Lyle
-1

Lo hago así cuando hay muchos puntos a utilizar ...

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

En clase 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
}

Así que ahora se crean POJO y enum obj. Ahora EnumTest lo configurará en el objeto de sesión usando en el servlet o clase de controlador session.setAttribute ("enumTest", EnumTest);

En la página JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Pavana
fuente