将数据列绑定到数据源中可能存在或可能不存在的属性的最佳方法是什么?
例如,如果您有一个类层次结构,其中某些子项可能属于具有该属性的子类型,则会发生这种情况。数据源包含各种子类类型。
<DataColumn outputText="#{item.property}" />
当其中一个子类中不存在该属性时,始终会产生一个PropertyNotFoundException。我不想在基类中包含该属性,因为根据业务规则它不应该存在。
你会如何解决这个问题?
答案 0 :(得分:8)
不改变课程,最好的办法就是在EL中做instanceof
。您可以通过检查Object#getClass()
获得的(简单)类名,然后选择EL中的Class#getName()
或Class#getSimpleName()
来完成此操作。
假设具有该属性的类具有完全限定名com.example.SubItem
,这是一个示例:
<h:outputText value="#{item.property}" rendered="#{item.class.name == 'com.example.SubItem'}" />
或
<h:outputText value="#{item.property}" rendered="#{item.class.simpleName == 'SubItem'}" />
答案 1 :(得分:4)
作为在EL中提供instanceof
功能的替代方法,您可以考虑向isInstanceOf()
bean添加ApplicationScoped
方法。我用的是:
@ManagedBean( name="app" )
@ApplicationScoped
public class ApplicationController implements Serializable {
public boolean isInstanceOf( Object o, String className ) throws ClassNotFoundException {
return Class.forName( className ).isInstance( o );
}
}
然后我从EL那里称之为:
<... rendered="#{app.isInstanceOf( someObject, 'java.lang.Object' )}">
通过一些调整,可以推广这个想法,以便于从EL调用任何静态方法。
答案 2 :(得分:3)
我认为在这种情况下,最好的方法是为视图层创建一个包含所有必要字段的自定义实体,并将要显示的项目转换为它。
答案 3 :(得分:0)
为什么不具有基类的布尔属性,该属性告诉您是否在子类中具有实际属性。这样你就可以在EL表达式中轻松使用三元运算符,如下所示:
<DataColumn outputText="#{item.hasProperty ? item.property : 'I don't have this property.'}" />
如果EL懒惰地评估表达式,这可能有效,但我不确定,现在无法检查。但无论如何这都是一个想法。
答案 4 :(得分:0)
根据您的模型,我认为您可能希望在辅助bean中执行更多工作,而不是尝试使其在实际的JSF页面上工作。
您可以将表绑定到bean
<h:dataTable binding="#{myBean.dataTable}" />
//BEAN
HtmlDataTable dataTable;
public DataTable getDataTable()
{
dataTable = new HtmlDataTable(); //etc...
//add the columns here based on the logic in code
}
然后实际通过动态添加组件来在bean内部进行渲染...如果你想要分离模型并且你需要页面是一个非常受控制的bean,那么上面的答案真的更像你之后。
或者如建议的那样,只需使用rendered属性并检查类名(注意空指针)。我定期做两件事,这实际上取决于我将在实际的JSF中使用多少复杂的布尔逻辑。