Existe-t-il un moyen d'effectuer une vérification instanceof
dans EL?
Par exemple.
<h:link rendered="#{model instanceof ClassA}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model instanceof ClassB}">
#{errorMessage2}
</h:link>
Vous pouvez comparer Class#getName()
ou, peut-être mieux, Class#getSimpleName()
à une String
.
<h:link rendered="#{model['class'].simpleName eq 'ClassA'}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model['class'].simpleName eq 'ClassB'}">
#{errorMessage2}
</h:link>
Notez qu'il est important de spécifier Object#getClass()
avec une accolade ['class']
car class
est un littéral Java réservé qui, sinon, renverrait une exception EL dans EL 2.2+.
L'alternative type-safe consiste à ajouter des public enum Type { A, B }
avec public abstract Type getType()
à la classe de base commune du modèle.
<h:link rendered="#{model.type eq 'A'}">
#{errorMessage1}
</h:link>
<h:link rendered="#{model.type eq 'B'}">
#{errorMessage2}
</h:link>
Toute valeur non valide lève ici une exception EL lors de l'exécution dans EL 2.2+.
Si vous utilisez OmniFaces , depuis la version 3.0, vous pouvez utiliser #{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>
Cela ne fonctionne pas dans EL
. Utilisez le haricot de sauvegarde pour cela:
public class MyBean {
public boolean getIsClassA() {
if(model instanceof ClassA) {
return true;
}
return false;
}
}
Et ensuite, faites le chèque en appelant le haricot:
<h:link outcome="#{PageNameA}?faces-redirect=true&" rendered="#{myBean.isClassA}">
#{errorMessage}
</h:link>
Ça marche:
rendered="#{node.getClass().getSimpleName() == 'Logt_anno'}"
Définir une fonction statique comme:
public boolean isInstanceOf( Object obj, Class targetClass) {
return targetClass.isInstance(obj);
}
Définissez une fonction EL personnalisée pour celle-ci et utilisez celle-ci . Nous pourrions également passer un nom de chaîne et effectuer un forName()
dans la méthode.
Il y a un moyen, voir
JSF EL: instanceof réservée mais pas encore implémentée?
Cependant, l'opérateur instanceof
n'est toujours pas implémenté, du moins dans Mojarra 2.1. S'il vous plaît voter pour le bug ici:
http://Java.net/jira/browse/JSP_SPEC_PUBLIC-113
La meilleure solution consiste à stocker le nom de la classe dans un getter de bean de sauvegarde au lieu de créer une méthode de test booléen pour chaque classe:
public String getSelectedNodeClassName()
{
return selectedNode.getClass().getSimpleName();
}
Ce serait donc un mélange de solutions BalusC et flash. Cependant, il serait beaucoup plus lisible dans JSF que BalusC et ressemblerait beaucoup à la future utilisation de l'opérateur instanceof
:
rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}"
Cela ne produira pas une méthode par test de classe sur le haricot de sauvegarde comme le suggère le flash. Cela pourrait être plus lent que Flash.
Pas très élégant car il mélange JSP EL et l'ancienne syntaxe expression, mais ne nécessite aucun code Java supplémentaire:
<%@ 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>
Vous pouvez utiliser un haricot d'assistance pour cela:
@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>
Cela présente l'avantage que l'héritage est pris en compte et que vous pouvez tester des classes que vous ne pouvez pas modifier (les deux inconvénients des solutions de BalusC).
Si vous aimez utiliser le nom de classe simple (et ne craignez pas les conflits de noms), vous pouvez utiliser une mappe de recherche que vous remplissez à la main ou avec un scanner de chemin de classe tel que 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);
}
}
Vous pouvez même déplacer la fonction d'assistance sur un 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>