在数据表的列中使用不同的(以编程方式创建的)JSF组件

在数据表的列中使用不同的(以编程方式创建的)JSF组件,jsf,jsf-2,Jsf,Jsf 2,对于JSF页面,我有以下xhtml代码: <h:dataTable value="#{bean.data}" var="elem"> <h:column> <h:panelGroup binding="#{elem.displayComponent}"/> </h:column> </h:dataTable> 一种实现可能是: public class LabelElement implements C

对于JSF页面,我有以下
xhtml
代码:

<h:dataTable value="#{bean.data}" var="elem">
    <h:column>
        <h:panelGroup binding="#{elem.displayComponent}"/>
    </h:column>
</h:dataTable>
一种实现可能是:

public class LabelElement implements CustomElementProvider {

    private UIPanel container;

    @Override
    UIPanel getDisplayComponent() {
        if (container == null) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            container = (UIPanel) facesContext.getApplication().createComponent(UIPanel.COMPONENT_TYPE);
            UIComponent inside = facesContext.getApplication().createComponent(HtmlOutputLabel.COMPONENT_TYPE);
            // fill label with data
            container.getChildren().add(inside);
        }
        return container;
    }

    // ... override setter
}
当支持bean
bean
提供控件时,这种方法有效,但当非托管数据对象提供控件时则无效。然后我得到一个例外:

javax.el.PropertyNotFoundException: Target Unreachable, identifier 'elem' resolved to null
有没有办法避免这种情况

到目前为止,我发现StackOverflow主要是有人想使用两个或更多预定义组件中的一个(请参阅)。这是行不通的,因为我希望能够通过编写新的数据对象来扩展系统,这些对象提供自己的组件实现,而无需修改
dataTable
xhtml
代码

我的问题的另一个解决方案是使用不同的接口:

public interface CustomElementProvider {
    String getCustomComponentName();
}
然后我呈现这个方法给出的自定义组件。但我不知道该怎么做

[更新]更清楚地说明我想要什么。这是有效的代码:

<h:dataTable value="#{preferences.preferenceList}" var="pref">
    <h:column>
        <f:facet name="header">
            <h:outputText value="Name"/>
        </f:facet>
        <h:outputLabel id="key" value="#{pref.key}"/>
    </h:column>
    <h:column>
        <f:facet name="header">
            <h:outputText value="Value"/>
        </f:facet>
        <h:inputText id="value" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.String'
                     or pref.valueTypeAsString eq 'java.lang.Integer'}"/>
        <h:selectBooleanCheckbox id="valueBool" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.Boolean'}"/>
        <h:selectOneMenu id="valueEnum" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.Enum'}">
            <f:selectItems value="#{pref.enumEntries}"/>
        </h:selectOneMenu>
    </h:column>
</h:dataTable>

目前唯一不太好的事情是,我需要为名为
preferences
的支持bean设置一个类似
preferences.boolProp
的EL名称,该bean有一个属性
boolProp

,为什么不使用XHTML而不是Java来声明/创建视图呢?在声明/创建所需的JSF组件树时,XHTML更直观,更不容易出错。如果您真的坚持使用Java代码,那么如果您首先创建并展示(工作!)XHTML等价物会更容易,那么我们可以更容易地告诉您如何在Java中实现同样的功能(您的具体问题与a.o.有着相同的基础;其他阅读材料:)@BalusC是对的。如果需要简单地创建组件,请在具有绑定的复合组件中使用c:If c:choose/when。效果很好。您可以得到一个简单的声明,其中包含一个选项,可以基于任何内容创建某些组件类型。@BalusC这就是问题所在。没有可用的XHTML等价物。事实上,我想要的是一种灵活的方式来编辑数据表中的数据。所以如果我有一个字符串,我想有一个输入字段。对于布尔型,我需要一个复选框,对于将来可能出现的任何情况,我需要一个匹配的花式控件。我可以通过xhtml添加所有具有相应的
rendered
属性(如中)的组件来实现这一点,但是我需要事先知道所有类型和匹配组件。
<h:dataTable value="#{preferences.preferenceList}" var="pref">
    <h:column>
        <f:facet name="header">
            <h:outputText value="Name"/>
        </f:facet>
        <h:outputLabel id="key" value="#{pref.key}"/>
    </h:column>
    <h:column>
        <f:facet name="header">
            <h:outputText value="Value"/>
        </f:facet>
        <h:inputText id="value" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.String'
                     or pref.valueTypeAsString eq 'java.lang.Integer'}"/>
        <h:selectBooleanCheckbox id="valueBool" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.Boolean'}"/>
        <h:selectOneMenu id="valueEnum" value="#{pref.value}"
            rendered="#{pref.valueTypeAsString eq 'java.lang.Enum'}">
            <f:selectItems value="#{pref.enumEntries}"/>
        </h:selectOneMenu>
    </h:column>
</h:dataTable>
public class BooleanPreference extends PreferenceBase<Boolean> {

    public BooleanPreference(String key, Boolean defaultValue, String elName, String description) {
        super(key, defaultValue, elName, description);
    }

    @Override
    public Boolean fromString(String strValue) {
        return Boolean.valueOf(strValue);
    }

    @Override
    public UIComponent getEditComponent() {
        HtmlSelectBooleanCheckbox checkbox = new HtmlSelectBooleanCheckbox();
        checkbox.setValueExpression("value", createValueExpression(String.format("#{%s.value}", getElName())));

        return checkbox;
    }
}