<f: viewParam> не устанавливается во время <h: form> отправки

Я хотел бы создать форму, чтобы просто изменить поля какого-либо объекта проекта.

Для этого я создал bean-объект с областью запроса и представление, которое вместе с конвертером сообщает бину, какая сущность редактируется.

боб

@Named
@RequestScoped
public class Bean {

    private Project selectedProject;

    public void setSelectedProject(Project project) {
        selectedProject= project;
    }

    public Project getSelectedProject() {
        return selectedProject;
    }

    public String save() {
        // Persist selectedProject...
        return null;
    }
}

Посмотреть

<ui:composition template="/templates/layout.xhtml"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">

<ui:define name="metadata">
    <f:metadata>
        <f:viewParam id="projectParam" name="project"
            value="#{bean.selectedProject}" converter="#{projectConverter}" />
    </f:metadata>
</ui:define>

<ui:define name="content">
    <h:form id="projectForm">

        <p:panel header="Project details">
            <h:panelGrid columns="2">

                <p:outputLabel for="title" value="Title" />
                <h:inputText id="title" value="#{bean.selectedProject.title}" />

                <p:outputLabel for="desc" value="Description" />
                <h:inputTextarea id="desc" value="#{bean.selectedProject.description}" />

            </h:panelGrid>

            <p:commandButton id="submitButton" type="submit"
                value="Save" action="#{bean.save}">
                    <f:param name="project" value="#{bean.selectedProject.id}" />
            </p:commandButton>

        </p:panel>

    </h:form>

</ui:define>
</ui:composition>

Загрузка представления изначально работает нормально, выбранный проект загружается, а поля формы заполняются свойствами проекта. Однако при сохранении формы я получаю следующую трассировку стека:

11:00:58,837 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (http--0.0.0.0-8080-3) /user/project.xhtml @42,70 value="#{bean.selectedProject.title}": Target Unreachable, 'selectedProject' returned null: javax.el.PropertyNotFoundException: /user/project.xhtml @42,70 value="#{bean.selectedProject.title}": Target Unreachable, 'selectedProject' returned null
    at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:95) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.validate(UIInput.java:960) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.processValidators(UIInput.java:698) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.primefaces.component.panel.Panel.processValidators(Panel.java:297) [primefaces-3.5.jar:]
    at javax.faces.component.UIForm.processValidators(UIForm.java:253) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.primefaces.component.layout.Layout.processValidators(Layout.java:246) [primefaces-3.5.jar:]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:489) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Thread.java:680) [classes.jar:1.6.0_51]

При отладке проблемы я обнаружил, что преобразователь действительно вызывается, но возвращенный проект не устанавливается в bean-компоненте до того, как произойдет описанный выше жизненный цикл. Если я возвращаю фиктивный проект в bean-компоненте, все работает нормально, выбранный проект в конечном итоге устанавливается, и я могу сохранить его с обновленными значениями.

Это ожидаемое поведение? Могу ли я запустить его, не возвращая фиктивный проект?

Я видел подходы с точки зрения видимости бобов. Поскольку мы используем CDI, я бы предпочел придерживаться аннотаций javax.enterprise. Если вы считаете, что остальная часть кода (шаблон, конвертер) имеет какое-либо отношение, я с удовольствием добавлю их.

1 ответ

Решение

Это ожидаемое поведение. С <f:viewParam /> вы устанавливаете значение в бине во время запроса GET. Значение установлено, поэтому ваша страница отображается правильно, однако ваш бин @RequestScopedпоэтому его состояние теряется от одного запроса к другому. Когда вы выполняете запрос POST с вашим p:commandButton, его значение на самом деле равно нулю. Чтобы решить это, вы должны использовать @ViewScoped боб.

Другие вопросы по тегам