instanceof check in EL expression language

删除回忆录丶 提交于 2019-12-17 10:47:27

问题


Is there a way to perform an instanceof check in EL?

E.g.

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

回答1:


You could compare Class#getName() or, maybe better, Class#getSimpleName() to a String.

<h:link rendered="#{model['class'].simpleName eq 'ClassA'}">      
    #{errorMessage1}
</h:link>
<h:link rendered="#{model['class'].simpleName eq 'ClassB'}">      
    #{errorMessage2}
</h:link>

Note the importance of specifying Object#getClass() with brace notation ['class'] because class is a reserved Java literal which would otherwise throw an EL exception in EL 2.2+.

The type safe alternative is to add some public enum Type { A, B } along with public abstract Type getType() to the common base class of the model.

<h:link rendered="#{model.type eq 'A'}">      
    #{errorMessage1}
</h:link>
<h:link rendered="#{model.type eq 'B'}">      
    #{errorMessage2}
</h:link>

Any invalid values would here throw an EL exception during runtime in EL 2.2+.

In case you're using OmniFaces, since version 3.0 you could use #{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>



回答2:


That doesn't work in EL. Use the backing bean for this:

public class MyBean {

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


}

And then do the check by calling the backing bean:

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




回答3:


it works:

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



回答4:


Define a static function like:

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

Define a custom EL function for it, and use that. We could also pass a string name and do a forName() inside the method.




回答5:


There is a way, see

JSF EL: instanceof reserved but not yet implemented?

However, the instanceof operator is still not implemented, at least in Mojarra 2.1. Please vote for the bug here:

http://java.net/jira/browse/JSP_SPEC_PUBLIC-113

The best workaround currently is probably to store the class name in a backing bean getter instead of creating a boolean test method for each class:

public String getSelectedNodeClassName()
{
    return selectedNode.getClass().getSimpleName();
}

So it would be a mix of BalusC's and flash's solutions. It would however be much more readable in JSF than BalusC's plus it pretty much resembles the future instanceof operator use:

rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}"

This will not produce one method per class test on the backing bean as flash suggested. This could be slower than flash's though.




回答6:


Not very elegant as it mixes JSP EL and the earlier expression syntax, but doesn't require any extra Java code:

<%@ 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>



回答7:


You could use a helper bean for that:

@ManagedBean
public class Helper {
  public boolean isInstance(Object bean, String fullyQualifiedClassName) {
    return Class.forName(fullyQualifiedClassName).isInstance(bean);
  }
}

Usage:

<h:link rendered="#{helper.isInstance(model, 'package.ClassA')}">
  #{errorMessage1}
</h:link>

This has the advantage that inheritance is taken into account and you can test for classes which you can't modify (both disadvantages of the solutions of BalusC).

If you like to use the simple class name (and don't fear name clashes), you could use a lookup map which you fill by hand or with a class path scanner like 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);
  }
}

You could even move the helper function to an 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 ...
}

Usage:

<h:link rendered="#{model.isInstanceOf('package.ClassA')}">
  #{errorMessage1}
</h:link>


来源:https://stackoverflow.com/questions/10314214/instanceof-check-in-el-expression-language

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!