webentwicklung-frage-antwort-db.com.de

instanz der Prüfung in EL-Ausdruckssprache

Gibt es eine Möglichkeit, eine instanceof-Prüfung in EL durchzuführen?

Z.B.

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

Sie könnten Class#getName() oder, vielleicht besser, Class#getSimpleName() mit einer String vergleichen.

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

Beachten Sie die Wichtigkeit der Angabe von Object#getClass() mit geschweiften Klammern ['class'], da class ein reserviertes Java-Literal ist, das sonst eine EL-Ausnahme in EL 2.2+ auslösen würde.

Die typsichere Alternative ist, der gemeinsamen Basisklasse des Modells etwas public enum Type { A, B } zusammen mit public abstract Type getType() hinzuzufügen.

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

Alle ungültigen Werte würden hier zur Laufzeit in EL 2.2+ eine EL-Ausnahme auslösen.

Falls Sie OmniFaces verwenden, können Sie seit Version 3.0 #{of:isInstance()} verwenden.

<h:link rendered="#{of:isInstance('com.example.ClassA', model)}">      
    #{errorMessage1}
</h:link>
<h:link rendered="#{of:isInstance('com.example.ClassB', model)}">      
    #{errorMessage2}
</h:link>
49
BalusC

Das funktioniert nicht in EL. Verwenden Sie dazu die Stützbohne:

public class MyBean {

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


}

Und dann überprüfen Sie, indem Sie die Hintergrundbohne aufrufen:

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

6
flash

es klappt:

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

Definieren Sie eine statische Funktion wie:

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

Definieren Sie eine benutzerdefinierte EL-Funktion und verwenden Sie .. .. Wir können auch einen String-Namen übergeben und eine forName() innerhalb der Methode ausführen.

3
manojm

Es gibt einen Weg, sehen Sie

JSF EL: Instanz von reserviert, aber noch nicht implementiert?

Der Operator instanceof ist jedoch immer noch nicht implementiert, zumindest in Mojarra 2.1. Bitte stimmen Sie für den Fehler hier:

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

Die beste Problemumgehung besteht derzeit wahrscheinlich darin, den Klassennamen in einem Backing Bean-Getter zu speichern, anstatt für jede Klasse eine boolesche Testmethode zu erstellen:

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

Es wäre also eine Mischung aus Lösungen von BalusC und Flash. Es ist jedoch in JSF viel besser lesbar als das von BalusC und ähnelt ziemlich der zukünftigen Verwendung des instanceof-Operators:

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

Dies führt nicht zu einer Methode pro Klassenprüfung auf der Stützbohne, wie von Flash vorgeschlagen. Dies könnte jedoch langsamer sein als Flash.

2
Kawu

Nicht sehr elegant, da sie JSP EL und die frühere Ausdruckssyntax mischt, aber keinen zusätzlichen Java Code benötigt:

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

Sie könnten dafür eine Helfer-Bean verwenden:

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

Verwendungszweck:

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

Dies hat den Vorteil, dass Vererbung berücksichtigt wird und Sie auf Klassen testen können, die Sie nicht ändern können (beide Nachteile der Lösungen von BalusC).

Wenn Sie den einfachen Klassennamen verwenden möchten (und keine Namenskollisionen befürchten), können Sie eine Lookup-Map verwenden, die Sie von Hand oder mit einem Klassenpfad-Scanner wie org.reflections füllen:

@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);
  }
}

Sie können sogar die Hilfsfunktion auf einen ELResolver verschieben:

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 ...
}

Verwendungszweck:

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