EL syntax to check if a set contains a specific En

2019-09-17 12:48发布

问题:

I have an Item object, which has a field that is a Set of ItemTypes:

public class Item {
    EnumSet<ItemType> itemTypeSet;

    ...

    public Set<ItemType> getItemTypeSet(){
        return this.itemTypeSet;
    }
}

ItemType is of course a simple Enum.

public Enum ItemType {
    BOLD, THIN, COOL, ROUND;
}

In my JSP I would like to use JSTL to see if an item has a specific ItemType, I tried to use the following three snippets but I get no errors and no results. I'm not sure why all 3 are failing. Could somebody explain, for each of these 3 cases, why the program doesn't work like I think it does, and provide a 4th alternative that's working :)?

<c:if test="${item.itemTypeSet.contains('BOLD')}">
    Method 1 works!
</c:if>
<c:if test="${item.itemTypeSet.contains(ItemType.valueOf('BOLD'))}">
    Method 2 works!
</c:if>
<c:if test="${item.itemTypeSet.contains(ItemType.BOLD)}">
    Method 3 works!
</c:if>

Important is that the ItemType enum is public and not inside another class. It is totally accessible for any other class, including the ones that resolve the EL/JSTL/JSP.

Note that iterating over all values in the enumset works fine:

<c:forEach items="${item.itemTypeSet}" var="itemType">
    <p>${itemType}</p>
</c:forEach>

gives as result:

BOLD
ROUND

回答1:

Method 3 will work in EL 3.0 (Tomcat 8, WildFly 8, GlassFish 4, etc and newer) provided that you imported the enum in JSP page context as instructed in How to reference constants in EL?

<@page import="com.example.ItemType" %>

Method 2 should theoretically work in EL 3.0 too, but it's clumsy as compared to 3.

Method 1 won't work at all as EL is not aware of the generic type of the collection and still assumes it plain String due to the ${'...'} syntax. Basically, it's doing "BOLD".equals(BOLD) under the covers which will never pass.

You'd best create a custom EL function on this. For a kickoff example of a custom EL function, head to the answer on this related question: How can i do a multiselect in jsp/jstl with selected value? You'd like to end up with something like this:

<c:if test="${my:containsEnum(item.itemTypeSet, 'BOLD')}">

And do the Java magic accordingly in the containsEnum(Set, String) function.