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.

Respuestas:


112

Una simple comparación con la cuerda funciona:

<c:when test="${someModel.status == 'OLD'}">

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>

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.


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.


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.


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!


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>

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>

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.


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

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

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}">
...

-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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.