ELでinstanceof
チェックを実行する方法はありますか?
例えば。
<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
は、EL 2.2以降ではEL例外をスローする予約済みのJavaリテラルであるためです。
タイプセーフな代替方法は、_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()
を実行することもできます。
方法があります、参照してください
JSF EL:instanceofは予約されていますが、まだ実装されていませんか?
ただし、instanceof
演算子は、少なくともMojarra 2.1ではまだ実装されていません。ここでバグに投票してください:
http://Java.net/jira/browse/JSP_SPEC_PUBLIC-11
現在、最善の回避策は、クラスごとにブールテストメソッドを作成する代わりに、バッキングBeanゲッターにクラス名を格納することです。
public String getSelectedNodeClassName()
{
return selectedNode.getClass().getSimpleName();
}
したがって、それはBalusCのソリューションとフラッシュのソリューションの混合になります。ただし、JSFではBalusCのそれよりもはるかに読みやすく、将来のinstanceof
演算子の使用にかなり似ています。
rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}"
これは、フラッシュが提案するように、バッキングBeanのクラステストごとに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>
そのためにヘルパー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>