子项的 JSF 自定义组件请求映射值 null

JSF custom component requestmap value null for children

我创建了一个组件,用于访问基于数字转换为另一种类型的通用对象。我在请求映射中使用 "var" 属性以允许我的组件中的子级访问该对象。尝试在子组件中访问由 "var" 命名的对象时,出现以下异常: javax.el.PropertyNotFoundException:目标无法到达,标识符 'objectName' 解析为空。

这是我的组件代码和标记:

@FacesComponent(value = "components.AgendaItemTextAccessor", createTag = true)
public class AgendaItemTextAccessor  extends UIComponentBase{
public String getVar(){
    return (String) getStateHelper().eval("var");
}
public void setVar(String var){
    getStateHelper().put("var", var);
}
public AgendaItemText getValue(){
    return (AgendaItemText) getStateHelper().eval("value");
}
public void setValue(AgendaItemObject text){
    getStateHelper().put("value", text);
}

@Override
public boolean getRendersChildren() {
    return true;
}

@Override
public void encodeChildren(FacesContext context) throws IOException{
    if ((context == null)){
        throw new NullPointerException();
    }

    AgendaItemText text = (AgendaItemText)getValue();
    String varname = getVar();
    Map<String, Object> requestMap = context.getExternalContext().getRequestMap();

    Object varStore = requestMap.get(varname); // in case this Object already exists in the requestMap,
                                        // emulate "scoped behavior" by storing the value and
                                        // restoring it after all rendering is done.

    if(text != null){
        requestMap.put(varname, text);
        for(UIComponent child: getChildren()){
            child.encodeAll(context);
        }         
        // restore the original value
        if(varStore != null){
            requestMap.put(varname, varStore);
        }else{
            requestMap.remove(varname);
        }
    }
}

@Override
public String getFamily() {
    return "components.AgendaItemTextAccessor";
}

标记

<xx:agendaItemTextAccessor value="#{itemValue}" var="itemVar">
    <p:inputText value="#{itemVar.text}">
        <p:ajax event="blur" listener="#{Controller.printMe(itemVar)}" />
    </p:inputText>
</xx:agendaItemTextAccessor>

We were instructed to create a component that takes in the abstract object and cast it base on a field that defines its type

您在实现功能需求方面走错了方向。 var 增加了不必要的复杂性。直接用#{itemValue}就可以了。在 EL 中,无论如何,一切都是 Object(反射,你知道的),所以绝对不需要在将它放回 EL 之前向上、向下、向左或向右投射。

<p:inputText value="#{itemValue.text}">
    <p:ajax event="blur" listener="#{controller.printMe(itemValue)}" />
</p:inputText>

至于具体的问题,你遇到它是因为你只在encodeChildren()期间设置它而不是在processDecodes()processValidators()processUpdates()和[=18=期间设置它].换句话说,它只在渲染响应阶段可用,而不是在它可能相关的所有其他阶段。不幸的是,您没有在任何地方显示完整的堆栈跟踪,但它应该指出哪个阶段有问题(我的有根据的猜测是 processValidators())。通常,var 仅在转发器或仅输出组件中实现。查看 source code of <ui:repeat> how to do it right (and peek in source code of <o:tree> 如何以 DRY 方式进行操作)。