Access Enum value using EL with JSTL
Asked Answered
H

13

108

I have an Enum called Status defined as such:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

I would like to access the value of VALID from a JSTL tag. Specifically the test attribute of the <c:when> tag. E.g.

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

I'm not sure if this is possible.

Hahnke answered 23/9, 2008 at 20:18 Comment(0)
H
117

A simple comparison against string works:

<c:when test="${someModel.status == 'OLD'}">
Hibernicism answered 15/12, 2008 at 14:27 Comment(6)
For those requiring a source: This is specified (for instance) in section 1.17 of the "Expression Language Specification, version 2.2", which is part of JSR-245.Tamikotamil
The JavaServer Pages™ Specification, Version 2.0 says in JSP.2.3.5.7: "• If A or B is String coerce both A and B to String, compare lexically"Physostomous
But you loose the advantage of having an enum: this could lead to cumbersome misunderstandings if the enum gets changed one day. Usually, if I find myself changing an enum, I feel pretty safe, and probably I wouldn't remember that string-to-enum-reference in that view...Queen
Right, it is better to place decision-making code out of the view. Yet sometimes one have to.Hibernicism
Is this comparing against the toString of the enum? So if you override the toString (e.g. you want a friendly display name), then you need to make sure you also change the value that is being matched against.Bronchiectasis
FWIW, today on my Java 8 (IBM Java for WebSphere, in case it matters), this doesn't seem to work. It seems to only work if comparing against the string value, which here would be lower case "old"Tumbler
C
54

If using Spring MVC, the Spring Expression Language (SpEL) can be helpful:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
Cirri answered 2/5, 2011 at 9:57 Comment(3)
Seems this doesn't work for inner enums? Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1005E:(pos 0): Type cannot be found 'my.package.model.EngagementRequest.EngagementStatus'Underclassman
Try to use 'my.package.model.EngagementRequest$EngagementStatus'Cirri
A good thing about this solution is that you get an error message if there is a mistake in your expression, which does not always happen with <c:if> and <c:when> (they fail quietly).Sapphirine
C
41

You have 3 choices here, none of which is perfect:

  1. You can use a scriptlet in the test attribute:

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

    This uses the enum, but it also uses a scriptlet, which is not the "right way" in JSP 2.0. But most importantly, this doesn't work when you want to add another condition to the same when using ${}. And this means all the variables you want to test have to be declared in a scriptlet, or kept in request, or session (pageContext variable is not available in .tag files).

  2. You can compare against string:

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

    This looks clean, but you're introducing a string that duplicates the enum value and cannot be validated by the compiler. So if you remove that value from the enum or rename it, you will not see that this part of code is not accessible anymore. You basically have to do a search/replace through the code each time.

  3. You can add each of the enum values you use into the page context:

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

    and then you can do this:

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

I prefer the last option (3), even though it also uses a scriptlet. This is because it only uses it when you set the value. Later on you can use it in more complex EL expressions, together with other EL conditions. While in option (1) you cannot use a scriptlet and an EL expression in the test attribute of a single when tag.

Cussedness answered 22/5, 2013 at 13:16 Comment(1)
Regarding option 2, the compiler can not verify it, but at runtime the string will be converted into an enum using Enum.valueOf(Class<T> enumType, String name) which will trigger an ELException if the enum has no constant with that name. The expression will not just always be false.Dragster
H
23

So to get my problem fully resolved I needed to do the following:

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

Then I was able to do:

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

which worked as expected.

Hahnke answered 24/9, 2008 at 21:9 Comment(1)
using scriptlets is bad style.Eutrophic
B
16

Here are two more possibilities:

JSP EL 3.0 Constants

As long as you are using at least version 3.0 of EL, then you can import constants into your page as follows:

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

However, some IDEs don't understand this yet (e.g. IntelliJ) so you won't get any warnings if you make a typo, until runtime.

This would be my preferred method once it gets proper IDE support.

Helper Methods

You could just add getters to your 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;
  }
}

Then in your JSP:

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

This is supported in all IDEs and will also work if you can't use EL 3.0 yet. This is what I do at the moment because it keeps all the logic wrapped up into my enum.

Also be careful if it is possible for the variable storing the enum to be null. You would need to check for that first if your code doesn't guarantee that it is not null:

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

I think this method is superior to those where you set an intermediary value in the JSP because you have to do that on each page where you need to use the enum. However, with this solution you only need to declare the getter once.

Bronchiectasis answered 7/7, 2017 at 8:46 Comment(3)
"JSP EL 3.0 Constants" part must be the accepted answer since it's the standard way to achieve the required result using built-in functionality. On a side note, InteliJ IDEA (at least Ultimate version 2017.2.4) does support it out of the box and shows list of available constants when you type ${MyEnum.}, put caret right after dot and press Ctrl+Space to show suggestions.Ketchup
[UPDATE] Seems like IntelliJ IDEA already fixed the issue mentioned in this answer.Decor
I appreciate this is a few years later, but thought I'd add a comment as it may help others. EL 3.0 doesn't pick up a Java enum if it is stored within another class. E.g. this works: public enum TestEnum { AWAITING, FILE_PRESENT, FILE_NOT_FOUND; } but this doesn't: public class TestClass { public enum TestEnum { AWAITING, FILE_PRESENT, FILE_NOT_FOUND; } } Which is very frustrating as I never dedicate a whole class file to an enum!Skell
A
10

For this purposes I do the following:

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

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

It's looks ugly, but works!

Ayana answered 10/7, 2009 at 15:32 Comment(0)
D
3

I do not have an answer to the question of Kornel, but I've a remark about the other script examples. Most of the expression trust implicitly on the toString(), but the Enum.valueOf() expects a value that comes from/matches the Enum.name() property. So one should use e.g.:

<% pageContext.setAttribute("Status_OLD", Status.OLD.name()); %>
...
<c:when test="${someModel.status == Status_OLD}"/>...</c:when>
Damnation answered 17/3, 2011 at 15:24 Comment(0)
A
2

Add a method to the enum like:

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

For example

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

Then you can use:

<c:if test="${myObject.myEnumProperty.string eq 'VALUE_2'}">...</c:if>
Aulic answered 15/12, 2010 at 1:34 Comment(0)
W
1

When using a MVC framework I put the following in my controller.

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

This allows me to use the following in my JSP Page.

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

It can also be used in your comparison

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

Which I prefer over putting in a string literal.

Welterweight answered 10/7, 2017 at 16:21 Comment(0)
K
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()}
  • Put the import at the top, in JSP page header
  • If you want to work with getStatus method, use #1
  • If you want to work with the enum element itself, use either #2 or #3
  • You can use == instead of eq
Kathlenekathlin answered 8/6, 2019 at 12:7 Comment(0)
S
-1

I generally consider it bad practice to mix java code into jsps/tag files. Using 'eq' should do the trick :

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Synchrocyclotron answered 24/11, 2009 at 2:17 Comment(3)
So it is a bad practice to use == instead of eq ? They do both exactly the same, so there's no means of a "trick".Annora
Of course, I wasn't making a statement regarding the use of eq vs ==. Many answers to this question involved inserting java code into jsp or tag files which can be a crutch. I favor keeping business logic in java code (where it can be unit tested easily and thoroughly) separate from display logic in the JSP.Synchrocyclotron
To me it seems an equally bad practice to insert magic strings into your JSP which can't be checked by the compiler when you want to refactor your enums. Seems like there's no good solution to this on either side.Vanadinite
G
-1

I do it this way when there are many points to use...

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}">
...
Glyndaglynias answered 12/11, 2018 at 11:23 Comment(0)
B
-2

In Java Class:

    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
}

So now POJO and enum obj is created. Now EnumTest you will set in session object using in the servlet or controller class session.setAttribute("enumTest", EnumTest );

In JSP Page

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

//TRUE??? THEN PROCESS SOME LOGIC
Belch answered 15/6, 2016 at 19:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.