class 的 EL 表达式
EL expression for class
我不明白如何在 EL 表达式中表示 Class
。
我有一个 EL 函数,它将 class 作为参数(即枚举 class)到 return 可能的枚举值。
我想将它作为 EL 表达式调用。例如。 ${myTld:enumer(com.example.enums.MyEnum)}
但是:
- 以上语法将 null 作为参数传递
- 使用
MyEnum.class
会抛出异常,例如表达式无法计算
如何在 EL 中表达一个 class 而不可能通过它的字符串表示?
以下作品
<function>
<description>
Returns the list of enum values for the given enum class
</description>
<name>enumer</name>
<function-class>com.example.Functions</function-class>
<function-signature>List enumer(java.lang.String)</function-signature>
</function>
${tld:enumer('com.example.MyEnum')}
我想要什么
<function-signature>List enumer(java.lang.Class)</function-signature>
我想您希望将 Class
参数传递给您的函数,以避免每次都使用 Class.forName()
解析字符串来提高性能...是吗?
如果是这样,我认为有一种方法...如果您事先知道 classes 您将函数作为参数传递,请使用 ServletContextListener
将它们放入您的应用程序范围。这可能如下所示:
@WebListener
public class MyEnumInitializer implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
Map<String, Class<?>> map = new HashMap<>();
map.put("MyEnum1", MyEnum1.class);
map.put("MyEnum2", MyEnum2.class);
// etc.
sce.getServletContext().addAttribute("myEnums", map);
}
public void contextDestroyed(ServletContextEvent sce) {}
}
如果您使用的是 3.0 之前的 Servlet API 版本,请丢弃上面的 @WebListener
注释并在您的 web.xml
文件中声明侦听器,如下所示:
<listener>
<listener-class>mypackage.MyEnumListener</listener-class>
</listener>
如果您的函数接受 Class
,您可以按如下方式使用它:
${tld:enumer(myEnums['MyEnum1'])}
仍然存在 String
到 Class
的映射,但它涉及使用 HashMap
中的 String
键定位 Class
对象,这比使用反射解析 Class
对象更快。
此外,如果您需要向此 HashMap
添加一个 class,您在初始化应用程序时无法预见,您仍然可以在任何可以访问 ServletContext
(HashMap
不是一成不变的)。例如,在任何接收 HttpServletRequest
作为参数的方法中:
public void aMethod(HttpServletRequest req, [other params]) {
// ...
Map<String, Class<?>> myEnums = (Map<String, Class<?>>) req.getSession().getServletContext().getAttribute("myEnums");
if (!myEnums.containsKey("aNewEnum")) {
myEnums.put("aNewEnum", NewEnum.class);
}
// ...
}
干杯,
杰夫
您不能在普通 EL 中表示 Class
。如果它是一个 bean 属性,你最多可以通过它,就像这样 ${myTld:enumer(bean.someEnumClass)}
返回 Class<? extends Enum>
,或者 ${myTld:enumer(bean.someEnum['class'])}
其中 someEnum
是实际的 Enum
,但仅此而已。将 class 名称作为 String
传递确实是您最好的选择。
如果您已经在使用 EL 3.0(可在 Tomcat 8、WildFly 8 等 Servlet 3.1 容器上使用),自定义函数的替代方法是立即将其导入 JSP 像下面这样使用新的 EL 3.0 ImportHandler
API:
${pageContext.ELContext.importHandler.importClass('com.example.enums.MyEnum')}
然后 ${MyEnum}
可以获得枚举。
<c:forEach items="${MyEnum.values()}" var="myEnumValue">
${myEnumValue}<br/>
</c:forEach>
或者,通过 servlet 上下文侦听器全局导入 ${MyEnum}
,如下所示:
@WebListener
public class Config implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
JspFactory.getDefaultFactory().getJspApplicationContext(event.getServletContext()).addELContextListener(new ELContextListener() {
@Override
public void contextCreated(ELContextEvent event) {
event.getELContext().getImportHandler().importClass(MyEnum.class.getName());
}
});
}
// ...
}
我不明白如何在 EL 表达式中表示 Class
。
我有一个 EL 函数,它将 class 作为参数(即枚举 class)到 return 可能的枚举值。
我想将它作为 EL 表达式调用。例如。 ${myTld:enumer(com.example.enums.MyEnum)}
但是:
- 以上语法将 null 作为参数传递
- 使用
MyEnum.class
会抛出异常,例如表达式无法计算
如何在 EL 中表达一个 class 而不可能通过它的字符串表示?
以下作品
<function>
<description>
Returns the list of enum values for the given enum class
</description>
<name>enumer</name>
<function-class>com.example.Functions</function-class>
<function-signature>List enumer(java.lang.String)</function-signature>
</function>
${tld:enumer('com.example.MyEnum')}
我想要什么
<function-signature>List enumer(java.lang.Class)</function-signature>
我想您希望将 Class
参数传递给您的函数,以避免每次都使用 Class.forName()
解析字符串来提高性能...是吗?
如果是这样,我认为有一种方法...如果您事先知道 classes 您将函数作为参数传递,请使用 ServletContextListener
将它们放入您的应用程序范围。这可能如下所示:
@WebListener
public class MyEnumInitializer implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
Map<String, Class<?>> map = new HashMap<>();
map.put("MyEnum1", MyEnum1.class);
map.put("MyEnum2", MyEnum2.class);
// etc.
sce.getServletContext().addAttribute("myEnums", map);
}
public void contextDestroyed(ServletContextEvent sce) {}
}
如果您使用的是 3.0 之前的 Servlet API 版本,请丢弃上面的 @WebListener
注释并在您的 web.xml
文件中声明侦听器,如下所示:
<listener>
<listener-class>mypackage.MyEnumListener</listener-class>
</listener>
如果您的函数接受 Class
,您可以按如下方式使用它:
${tld:enumer(myEnums['MyEnum1'])}
仍然存在 String
到 Class
的映射,但它涉及使用 HashMap
中的 String
键定位 Class
对象,这比使用反射解析 Class
对象更快。
此外,如果您需要向此 HashMap
添加一个 class,您在初始化应用程序时无法预见,您仍然可以在任何可以访问 ServletContext
(HashMap
不是一成不变的)。例如,在任何接收 HttpServletRequest
作为参数的方法中:
public void aMethod(HttpServletRequest req, [other params]) {
// ...
Map<String, Class<?>> myEnums = (Map<String, Class<?>>) req.getSession().getServletContext().getAttribute("myEnums");
if (!myEnums.containsKey("aNewEnum")) {
myEnums.put("aNewEnum", NewEnum.class);
}
// ...
}
干杯,
杰夫
您不能在普通 EL 中表示 Class
。如果它是一个 bean 属性,你最多可以通过它,就像这样 ${myTld:enumer(bean.someEnumClass)}
返回 Class<? extends Enum>
,或者 ${myTld:enumer(bean.someEnum['class'])}
其中 someEnum
是实际的 Enum
,但仅此而已。将 class 名称作为 String
传递确实是您最好的选择。
如果您已经在使用 EL 3.0(可在 Tomcat 8、WildFly 8 等 Servlet 3.1 容器上使用),自定义函数的替代方法是立即将其导入 JSP 像下面这样使用新的 EL 3.0 ImportHandler
API:
${pageContext.ELContext.importHandler.importClass('com.example.enums.MyEnum')}
然后 ${MyEnum}
可以获得枚举。
<c:forEach items="${MyEnum.values()}" var="myEnumValue">
${myEnumValue}<br/>
</c:forEach>
或者,通过 servlet 上下文侦听器全局导入 ${MyEnum}
,如下所示:
@WebListener
public class Config implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
JspFactory.getDefaultFactory().getJspApplicationContext(event.getServletContext()).addELContextListener(new ELContextListener() {
@Override
public void contextCreated(ELContextEvent event) {
event.getELContext().getImportHandler().importClass(MyEnum.class.getName());
}
});
}
// ...
}