4
votes

Im sure why, but my viewscoped-bean doesnt get persisted when redisplaying the same page. Im wondering if this is because of the use of facelet templates ?

Here's what i did to help me troubleshoot the problem :

  1. Add a @PostConstruct method and debug from there
  2. Add some debugging in a setter and getter method
  3. The ViewScoped debugging seems to have lots of PostConstruct method calls
  4. And yes, the state is not persisted (submit, set flag to true, but when redisplaying the flag is back false again)
  5. Try changing the scope to session, got an error that says "org.glassfish.deployment.common.DeploymentException: WELD-000072 Managed bean declaring a passivating scope must be passivation capable" when restarting my glassfish. Had to make my bean serializable to skip this error.
  6. And in session scope bean, PostConstruct is called only once, and the state persisted

I wonder what went wrong with my ViewScope case ?

Here's my facelet file : "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<h:head>
    <title>#{msgs.title}</title>
    <h:outputStylesheet library="css" name="main.css" />
</h:head>
<h:body>
    <ui:composition template="/template/masterlayout.xhtml">
        <ui:define name="windowTitle">Checkbox Lab</ui:define>
        <ui:define name="heading">Checkbox Lab</ui:define>
        <ui:define name="content">
            <h:form>
                <p:messages id="messages" globalOnly="true"/>
                <h:panelGrid columns="3" styleClass="bordered">
                    <h:outputLabel for="Married" value="Married" />
                    <h:selectBooleanCheckbox label="Married" id="Married" 
                         value="#{checkboxLabBean.married}" />
                    <p:message for="Married"/>

                    <p:panel header="debug info" id="debugPanel"
                        toggleable="true" toggleSpeed="300" >
                            <h:panelGrid columns="2">
                            <h:outputText value="rendered :"/> 
                            #{checkboxLabBean.submitted}

                            <h:outputText value="married status :"/> 
                            #{checkboxLabBean.married}
                            </h:panelGrid>
                    </p:panel>
                </h:panelGrid>
                <h:commandButton value="Refresh"
                    action="#{checkboxLabBean.submit}"/>
            </h:form>
        </ui:define>
    </ui:composition>
</h:body>
</html>

And here's my bean :

package user.ui;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.bean.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class CheckboxLabBean implements Serializable {
    private boolean married = true;
    private boolean submitted;

    @PostConstruct
    public void debugPostConstruct() {
        System.out.println("Post Construct !");
    }

    public boolean isMarried() {
        return married;
    }
    public void setMarried(boolean married) {
        this.married = married;
    }
    public boolean isSubmitted() {
        System.out.println("returning submit : " + this.submitted);
        return submitted;
    }
    public void setSubmitted(boolean submitted) {
        this.submitted = submitted;
    }

    public String submit() {
        System.out.println("setting submit to true");
        this.submitted = true;
        return null;
    }
}

Here's the output of my viewscope and sessionscope logs :

view scoped first opened after restarting web app :

[#|2010-12-24T11:01:11.307+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:01:11.310+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:01:11.310+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|returning submit : false|#]

[#|2010-12-24T11:01:11.311+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:01:11.322+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:01:11.322+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=34;_ThreadName=Thread-1;|Post Construct !|#]

view scoped after clicking on the refresh button

[#|2010-12-24T11:02:46.129+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.130+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.131+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.131+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.131+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|setting submit to true|#]

[#|2010-12-24T11:02:46.133+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.134+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.134+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|returning submit : false|#]

[#|2010-12-24T11:02:46.134+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.136+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T11:02:46.136+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|Post Construct !|#]

session scoped first opened after restarting web app :

[#|2010-12-24T10:58:54.610+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=32;_ThreadName=Thread-1;|Post Construct !|#]

[#|2010-12-24T10:58:54.612+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=32;_ThreadName=Thread-1;|returning submit : false|#]

session scoped after clicking on the refresh button :

[#|2010-12-24T10:59:14.613+0700|INFO|glassfish3.0.1|org.hibernate.validator.engine.resolver.DefaultTraversableResolver|_ThreadID=37;_ThreadName=Thread-1;|Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.|#]

[#|2010-12-24T10:59:14.615+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|setting submit to true|#]

[#|2010-12-24T10:59:14.617+0700|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=37;_ThreadName=Thread-1;|returning submit : true|#]

3

3 Answers

6
votes

The problem seems to be that you are declaring your bean to be a CDI managed bean, not a JSF managed bean. @ViewScoped is a JSF specific scope that is not natively supported by CDI.

CDI does allow you to create custom scopes, so you can build support for it. In fact, this has already been done. See this: http://seamframework.org/Community/JSF2ViewScopeInCDI

Without using any extensions, the following code works perfectly well:

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class MyBean {

    String state = "";

    @PostConstruct
    public void test() {
        System.out.println("pc called");
        state = "state set";
    }

    public String getState() {
        return state;
    }

    public String action() {
        return "";
    }
}

And the following Facelet:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
    <h:body>

        #{myBean.state}

        <h:form>
            <h:commandButton value="test" action="#{myBean.action}"/>
        </h:form>
    </h:body>
</html>

The post construct method will only be called once now, and after you press the command button the page will refreshed but the state will be retained.

2
votes

Seam Faces 3 provides a @ViewScoped annotation for CDI beans, along with a ton of other features to bridge the gap between CDI and JSF.

1
votes

Based on advice posted here, I have started using MyFaces CODI to solve this problem. I can't tell you if Seam or CODI is better, but at least it lets me move past trying to puzzle out scopes and get on with coding the application.