<h:selectBooleanCheckbox/> 使用 bean 方法的结果时出现 PropertyNotFoundException

PropertyNotFoundException when using bean's method's result for <h:selectBooleanCheckbox/>

环境:

当前代码:

我有以下 XHTML 页面:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:p="http://primefaces.org/ui"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                template="/WEB-INF/pages/main/admin.xhtml">

    <ui:define name="contentBody">
        <p:dataTable widgetVar="weekdayTable"
                     value="#{weekdayList.countries}"
                     var="ctr"
                     styleClass="weekdaysManagementDatatable">

            <p:column width="100"
                      sortBy="#{ctr.desc}"
                      headerText="#{msg['page.admin.weekday.list.country']}">
                <h:outputText value="#{ctr.desc}" />
            </p:column>

            <c:forEach items="#{weekdayList.weekdays}" var="day">
                <c:set var="open" value="#{weekdayList.checkOpen(ctr.id, day.date)}"/>
                <p:column width="20" headerText="#{utils.dateToDayWeek(day.date)}">
                    <h:selectBooleanCheckbox value="#{open}">
                        <p:ajax listener="#{weekdayList.handleDay(ctr.id, day.id)}" />
                    </h:selectBooleanCheckbox>
                </p:column>
            </c:forEach>
        </p:dataTable>
    </ui:define>
</ui:composition>

关联的 bean 如下:

@Named("weekdayList")
@Scope("session")
public class AdminWeekdayListController implements Serializable {

    ...

    public boolean checkOpen(String ctrId, Date date) {
        Country ctr = countryDao.getById(ctrId);
        List<WeekDay> list = weekdaysMap.get(ctr);

        if (list == null) {
            return true;
        }

        WeekDay day = new WeekDay();
        day.setDate(date);

        for (WeekDay wd : list) {
            if (wd.compareTo(day) == 0) {
                return wd.isOpen();
            }
        }
        return true;
    }
}

我有另一个 bean 维护要显示的当前页面,整个应用程序是用 AJAX 制作的。用户始终在同一页面上,内容是动态加载的。

问题:

当我重新加载 (F5) 页面时,一切似乎都正常工作。 但是,如果我进行正常导航(AJAX 加载),我会得到一个 PropertyNotFoundException...

这是堆栈跟踪:

SEVERE: javax.faces.component.UpdateModelException: javax.el.PropertyNotFoundException: /WEB-INF/pages/main/admin/weekdayList.xhtml @32,47 value="#{open}": /WEB-INF/pages/main/admin/weekdayList.xhtml @29,74 value="#{weekdayList.checkOpen(ctr.id, day.date)}": Property 'checkOpen' not found on type stomac.web.controller.AdminWeekdayListController
    at javax.faces.component.UIInput.updateModel(UIInput.java:867)
    at javax.faces.component.UIInput.processUpdates(UIInput.java:749)
    at org.primefaces.component.api.UIData.process(UIData.java:342)
    at org.primefaces.component.api.UIData.processChildren(UIData.java:323)
    at org.primefaces.component.api.UIData.processPhase(UIData.java:285)
    at org.primefaces.component.api.UIData.processUpdates(UIData.java:271)
    at org.primefaces.component.datatable.DataTable.processUpdates(DataTable.java:651)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1254)
    at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:769)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1125)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1059)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:497)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:248)
    at org.eclipse.jetty.io.AbstractConnection.run(AbstractConnection.java:540)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:610)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:539)
    at java.lang.Thread.run(Thread.java:745)
Caused by: javax.el.PropertyNotFoundException: /WEB-INF/pages/main/admin/weekdayList.xhtml @32,47 value="#{open}": /WEB-INF/pages/main/admin/weekdayList.xhtml @29,74 value="#{weekdayList.checkOpen(ctr.id, day.date)}": Property 'checkOpen' not found on type stomac.web.controller.AdminWeekdayListController
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:133)
    at javax.faces.component.UIInput.updateModel(UIInput.java:832)
    ... 36 more
Caused by: javax.el.PropertyNotFoundException: /WEB-INF/pages/main/admin/weekdayList.xhtml @29,74 value="#{weekdayList.checkOpen(ctr.id, day.date)}": Property 'checkOpen' not found on type stomac.web.controller.AdminWeekdayListController
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:133)
    at org.apache.el.parser.AstIdentifier.setValue(AstIdentifier.java:129)
    at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:260)
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
    ... 37 more
Caused by: javax.el.PropertyNotFoundException: Property 'checkOpen' not found on type stomac.web.controller.AdminWeekdayListController
    at javax.el.BeanELResolver$BeanProperties.get(BeanELResolver.java:245)
    at javax.el.BeanELResolver$BeanProperties.access0(BeanELResolver.java:222)
    at javax.el.BeanELResolver.property(BeanELResolver.java:332)
    at javax.el.BeanELResolver.getType(BeanELResolver.java:82)
    at com.sun.faces.el.DemuxCompositeELResolver._getType(DemuxCompositeELResolver.java:215)
    at com.sun.faces.el.DemuxCompositeELResolver.getType(DemuxCompositeELResolver.java:242)
    at org.apache.el.parser.AstValue.setValue(AstValue.java:199)
    at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:260)
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
    ... 40 more

但是让我认为问题不是出自我的 bean 的原因是,如果我从 <h:selectBooleanCheckbox/> 的值中删除 #{open} 它会完美地工作(除了复选框不是检查我想要的方式):

<c:forEach items="#{weekdayList.weekdays}" var="day">
    <c:set var="open" value="#{weekdayList.checkOpen(ctr.id, day.date)}"/>
    <p:column width="20" headerText="#{utils.dateToDayWeek(day.date)}">
        #{open}
        <h:selectBooleanCheckbox value="true">
            <p:ajax listener="#{weekdayList.handleDay(ctr.id, day.id)}" />
        </h:selectBooleanCheckbox>
    </p:column>
</c:forEach>

如您所见,我一直在使用 #{open},但不在 value 属性中。

问题:

我做错了什么?我错过了什么吗?有错误吗?

谢谢。

它是 Taghandler 和 UI 组件的生命周期。

JSF 中的 JSTL 标签不代表组件,并且在构建视图后永远不会成为组件树的一部分。

TagHandlers 负责构建树,"Once they have done their job, they expire"。这意味着,它们仅在视图构建阶段可用。另一方面 UI-组件 运行 在视图渲染阶段。

所以...我找到了 "solution",并回答了我自己的问题。

我为方法 checkOpen 添加了伪造的 getter 和 setter。所以豆子看起来像这样:

@Named("weekdayList")
@Scope("session")
public class AdminWeekdayListController implements Serializable {

    ...

    public boolean getCheckOpen() {
        return true;
    }

    public void setCheckOpen(boolean b) {
    }

    public boolean checkOpen(String ctrId, Date date) {
        Country ctr = countryDao.getById(ctrId);
        List<WeekDay> list = weekdaysMap.get(ctr);

        if (list == null) {
            return true;
        }

        WeekDay day = new WeekDay();
        day.setDate(date);

        for (WeekDay wd : list) {
            if (wd.compareTo(day) == 0) {
                return wd.isOpen();
            }
        }
        return true;
    }
}

这样 JSF 认为 checkOpen 是一个有效的 (read/write) 属性,BUT 调用 checkOpen(String ctrId, Date date)。它从不调用 getter 或 setter...

如果有人能解释一下,我将不胜感激。如果有人有更好的解决方案,我会倾听。