instanceof
有没有办法在 EL中进行检查?
例如
<h:link rendered="#{model instanceof ClassA}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model instanceof ClassB}">
#{errorMessage2}
</h:link>
instanceof
有没有办法在 EL中进行检查?
例如
<h:link rendered="#{model instanceof ClassA}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model instanceof ClassB}">
#{errorMessage2}
</h:link>
您可以比较Class#getName()
,或者可能更好,Class#getSimpleName()
与String
.
<h:link rendered="#{model['class'].simpleName eq 'ClassA'}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model['class'].simpleName eq 'ClassB'}">
#{errorMessage2}
</h:link>
Object#getClass()
请注意使用大括号表示法指定的重要性,['class']
因为class
它是保留的 Java 文字,否则会在 EL 2.2+ 中引发 EL 异常。
类型安全的替代方法是在模型的公共基类中添加public enum Type { A, B }
一些public abstract Type getType()
。
<h:link rendered="#{model.type eq 'A'}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model.type eq 'B'}">
#{errorMessage2}
</h:link>
任何无效值都会在 EL 2.2+ 的运行时引发 EL 异常。
如果您使用的是OmniFaces,从 3.0 版开始,您可以使用#{of:isInstance()}
.
<h:link rendered="#{of:isInstance('com.example.ClassA', model)}">
#{errorMessage1}
</h:link>
<h:link rendered="#{of:isInstance('com.example.ClassB', model)}">
#{errorMessage2}
</h:link>
这在EL
. 为此使用支持 bean:
public class MyBean {
public boolean getIsClassA() {
if(model instanceof ClassA) {
return true;
}
return false;
}
}
然后通过调用支持 bean 进行检查:
<h:link outcome="#{PageNameA}?faces-redirect=true&" rendered="#{myBean.isClassA}">
#{errorMessage}
</h:link>
有用:
rendered="#{node.getClass().getSimpleName() == 'Logt_anno'}"
定义一个静态函数,如:
public boolean isInstanceOf( Object obj, Class targetClass) {
return targetClass.isInstance(obj);
}
为它定义一个自定义的 EL 函数,并使用它。我们还可以传递一个字符串名称并forName()
在方法内部进行操作。
有办法,看
但是,该instanceof
运算符仍然没有实现,至少在 Mojarra 2.1 中是这样。请在此处为错误投票:
http://java.net/jira/browse/JSP_SPEC_PUBLIC-113
目前最好的解决方法可能是将类名存储在支持 bean getter 中,而不是为每个类创建一个布尔测试方法:
public String getSelectedNodeClassName()
{
return selectedNode.getClass().getSimpleName();
}
所以它将是 BalusC 和 flash 解决方案的混合体。然而,它在 JSF 中的可读性比 BalusC 的要高得多,而且它非常类似于未来的instanceof
运算符使用:
rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}"
这不会像 flash 建议的那样在支持 bean 上为每个类测试生成一个方法。不过,这可能比 Flash 慢。
不是很优雅,因为它混合了JSP EL和早期的表达式语法,但不需要任何额外的Java代码:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="interfaceClass" value="<%=com.example.ClassA.class%>"/>
<c:set var="implementationClass" value="${model['class']}"/>
<c:if test="${interfaceClass.isAssignableFrom(implementationClass)}">
<%-- Your logic here. --%>
</c:if>
您可以为此使用辅助 bean:
@ManagedBean
public class Helper {
public boolean isInstance(Object bean, String fullyQualifiedClassName) {
return Class.forName(fullyQualifiedClassName).isInstance(bean);
}
}
用法:
<h:link rendered="#{helper.isInstance(model, 'package.ClassA')}">
#{errorMessage1}
</h:link>
这样做的好处是考虑了继承,并且您可以测试您无法修改的类(BalusC 解决方案的两个缺点)。
如果您喜欢使用简单的类名(并且不担心名称冲突),您可以使用手动填写的查找图或使用类路径扫描器(如org.reflections):
@ManagedBean
@ApplicationScoped
public class Helper {
private Map<String, Class<? extends MyBaseClass>> classes =
new Reflections("myrootpackage").getSubTypesOf(MyBaseClass.class).stream()
.collect(Collectors.toMap(Class::getSimpleName, Function.identity()));
public boolean isInstance(Object bean, String simpleClassName) {
final Class<? extends MyBaseClass> c = this.classes.get(simpleClassName);
return c != null && c.isInstance(bean);
}
}
您甚至可以将辅助函数移动到 ELResolver:
public class InstanceOfELResolver extends ELResolver {
public Object invoke(final ELContext context, final Object base,
final Object method, final Class<?>[] paramTypes, final Object[] params) {
if ("isInstanceOf".equals(method) && params.length == 1) {
context.setPropertyResolved(true);
try {
return params[0] != null && Class.forName(params[0].toString()).isInstance(base);
} catch (final ClassNotFoundException e) {
return false;
}
}
return null;
}
// ... All other methods with default implementation ...
}
用法:
<h:link rendered="#{model.isInstanceOf('package.ClassA')}">
#{errorMessage1}
</h:link>