instanceof检查EL表达式语言

时间:2012-04-25 10:55:48

标签: jsf el instanceof

有没有办法在EL中执行instanceof检查?

E.g。

<h:link rendered="#{model instanceof ClassA}">      
    #{errorMessage1}
</h:link>
<h:link rendered="#{model instanceof ClassB}">      
    #{errorMessage2}
</h:link>

7 个答案:

答案 0 :(得分:51)

您可以将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>

答案 1 :(得分:6)

这在EL中不起作用。使用支持bean:

public class MyBean {

    public boolean getIsClassA() {
        if(model instanceof ClassA) {
            return true;
        }
        return false;
    }


}

然后通过调用支持bean进行检查:

<h:link outcome="#{PageNameA}?faces-redirect=true&amp;" rendered="#{myBean.isClassA}">      
    #{errorMessage}
</h:link>

答案 2 :(得分:4)

它有效:

rendered="#{node.getClass().getSimpleName() == 'Logt_anno'}"

答案 3 :(得分:3)

定义一个静态函数,如:

public boolean isInstanceOf( Object obj, Class targetClass) {
        return targetClass.isInstance(obj);
    }

为它定义自定义EL函数,并使用它。 我们也可以传递字符串名称并在方法中执行forName()

答案 4 :(得分:2)

有办法,见

JSF EL: instanceof reserved but not yet implemented?

但是,至少在Mojarra 2.1中,instanceof运算符仍未实现。请在这里投票支持错误:

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建议的那样在back bean上为每个类测试生成一个方法。这可能比闪光灯慢。

答案 5 :(得分:1)

不太优雅,因为它混合了 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>

答案 6 :(得分:0)

您可以使用辅助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>