为什么我不能在复合组件的encodeBegin中设置f:selectItems?

时间:2013-10-06 06:46:30

标签: jsf-2 composite-component

我正在尝试理解如何编写复合组件,并且遵循了balusc和其他人的优秀示例,但我遗漏了一些东西。

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite">

<cc:interface componentType="simpleComponent">
    <cc:attribute name="value" required="true" type="example.LanguageDefinition"/>
    <cc:attribute name="possibilities" default="de_DE" type="java.lang.String"/>
</cc:interface>

<cc:implementation>     
    <p:selectOneMenu binding="#{cc.inputComponent}" converter="omnifaces.SelectItemsConverter" var="l"
        value="#{cc.attrs.value}">
        <p:ajax update="@form"/>
        <f:selectItems value="#{cc.languages}" var="l" itemLabel="#{l.label}"
            itemValue="#{l}" />
        <p:column>#{l.label}</p:column>
        <p:column>
            <p:graphicImage name="#{l.imgPath}" />
        </p:column>
    </p:selectOneMenu>      
</cc:implementation>

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;

import example.LanguageDefinition;

@FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {

private UIInput  inputComponent;

public UIInput getInputComponent() {
    return inputComponent;
}

public void setInputComponent(UIInput inputComponent) {
    this.inputComponent = inputComponent;
}

@Override
public Object getSubmittedValue() {
    return inputComponent.getSubmittedValue();
}

@Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) {
   return (String) newSubmittedValue;
}

@Override
public String getFamily() {
    return UINamingContainer.COMPONENT_FAMILY;
}

@Override
public void encodeBegin(FacesContext context) throws IOException {
    String possibilities = getAttributeValue("possibilities", "en_US");
    // In theory, build based on incoming possibilities, now hard code
    List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
    languages.add(new LanguageDefinition("pt_PT",
            "images/flags/PT.gif", "Português (Portugal)"));
    languages.add(new LanguageDefinition("cs_CZ",
            "images/flags/CZ.gif", "Czech (Czech Republic)"));
    getStateHelper().put("languages", languages);
    super.encodeBegin(context);
}

@SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
    return (List<LanguageDefinition>) getStateHelper().get("languages");
}

/**
 * Return specified attribute value or otherwise the specified default if it's null.
 */
@SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
    T value = (T) getAttributes().get(key);
    return (value != null) ? value : defaultValue;
}
}

这不能像这样调用:

<ex:simpleComponent value="#{compBean.selected}"/>

一切都很好,但提交的值永远不会传递回我的“compBean”。但是,如果我以任何其他方式设置selectItems“语言”,而不是在encodeBegin中设置它,它可以...作为带有getter和setter的成员变量,或使用此代码:

<c:set target="#{cc}" property="possibilities" value="#{cc.attrs.possibilities}"/>

结合这个更简单的课程:

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;

import example.LanguageDefinition;

@FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {

@Override
public String getFamily() {
    return UINamingContainer.COMPONENT_FAMILY;
}

public void setPossibilities(String possibilities) {
    if (getStateHelper().get("possibilities") == null) {
        List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
        languages.add(new LanguageDefinition("pt_PT",
                "images/flags/PT.gif", "Português (Portugal)"));
        languages.add(new LanguageDefinition("cs_CZ",
                "images/flags/CZ.gif", "Czech (Czech Republic)"));
        getStateHelper().put("languages", languages);
getStateHelper().put("possibilities", possibilities);
    }
}

public String getPossibilities() {
    return (String) getStateHelper().get("possibilities");
}

@SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
    return (List<LanguageDefinition>) getStateHelper().get("languages");
}
}

但是,这样做是不对的(不是balusc的方式),所以我只是想了解。哪种方式更好?假设第一个,为什么我的不工作?

谢谢!

1 个答案:

答案 0 :(得分:1)

所以......这不起作用的原因是因为我忘了在我的自定义下拉列表值对象“example.LanguageDefinition”上实现Serializable。

希望下一个人只要我这样做就不必在大海捞针中寻找此针:)