比较 EL 内的枚举值失败

Comparing enum value inside EL fails

我正在尝试比较 EL 中 JSP 页面中的 enum。这应该支持 EL 3.0 版——我正在使用——及更高版本。这是我使用的代码和配置文件:

index.jsp:

<%@page import="net.myapp.MyClass" %>
<%@page import="net.myapp.MyClass.NestedEnum" %>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@page isELIgnored="false" %> <%-- default --%>

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<%
    MyClass mc = new MyClass();
    MyClass.NestedEnum[] enums = new MyClass.NestedEnum[]
        {MyClass.NestedEnum.NE_VALUE_A, MyClass.NestedEnum.NE_VALUE_B};
    request.setAttribute("enums", enums);
%>

<html>
<body>
<h2>Enums in EL</h2>

<c:forEach var="evalue" items="${enums}">
    <c:choose>
        <c:when test="${evalue == NE_VALUE_A}">
            Value is NE_VALUE_A.
        </c:when>
        <c:when test="${evalue == NestedEnum.NE_VALUE_A}">
            Value is NestedEnum.NE_VALUE_A.
        </c:when>
            <%-- This causes: javax.el.PropertyNotFoundException: No public static field named [NestedEnum] was found on (exported for Java 9+) class [net.myapp.MyClass]
        <c:when test="${evalue == MyClass.NestedEnum.NE_VALUE_A}">
            Value is MyClass.NestedEnum.NE_VALUE_A.
        </c:when>
            --%>
        <c:otherwise>
            Not value NE_VALUE_A. Actual value: ${evalue}
        </c:otherwise>
    </c:choose>
         <br/>
</c:forEach>

</body>
</html>

MyClass.java:

package net.myapp;

public class MyClass {
 
    private final NestedEnum value = NestedEnum.NE_VALUE_A;

    public static enum NestedEnum {
        NE_VALUE_A, NE_VALUE_B
    }

    public NestedEnum getValue() {
        return value;
    }

}

web.xml:

<web-app id="my-webapp" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <display-name>Archetype Created Web Application</display-name>

</web-app>

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-webapp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-webapp Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
<!--    <dependency>
      <groupId>javax.el</groupId>
      <artifactId>javax.el-api</artifactId>
      <version>3.0.0</version>
    </dependency>-->
  </dependencies>
  <build>
    <finalName>my-webapp</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.2</version>
      </plugin>
    </plugins>
  </build>
  <properties>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
</project>

when 块中的比较总是失败,我得到了 otherwise 块的输出。如果我使用字符串比较,例如

<c:when test="${evalue == 'NE_VALUE_A'}">

那么比较成功。但是,我想知道为什么与枚举值的比较失败。

PS: 该应用程序部署在 tomcat 服务器上,版本 9.0.31。 OS 使用 Java 11.

最简单的方法是将它与字符串进行比较:

<c:when test="${evalue == 'NE_VALUE_A'}">

这是因为 EL 的类型强制规则。

the EL specification 的第 1.8.2 节说以下强制规则适用于相等比较:

If A or B is an enum coerce both A and B to enum, apply operator

第 1.18.6 节说明了强制转换为枚举类型“T”的规则:

If A is a String call Enum.valueOf(T.getClass(), A) and return the result.

支持您一直尝试使用的语法,但事实证明无法使用 <%page import="…" %> 指令成功导入嵌套的 class 名称。这可能是因为真正的 class 名称类似于 net.myapp.MyClass$NestedEnum.

不知道能不能把那个名字传给<%page import指令。我从来没有尝试过。

(而且我一直想知道为什么常规 Java 编译器允许在常规 import 语句中嵌套 class 名称而没有单词 static;我可以'在 Java 语言规范中找不到对它的支持。)

如果您将枚举类型设置为 top-level class,您的 EL 测试应该有效。