In other words, your @ViewScoped
bean behaves like a @RequestScoped
bean. It’s been recreated from scratch on every postback request. There are many possible causes for this, most of which boils down that the associated JSF view is not available anymore in the JSF state which in turn is by default associated with the HTTP session.
Provided that you can assure that the HTTP session itself is not the root cause of the problem, i.e. when @SessionScoped
works absolutely fine, then walk through the below list of possible causes. Otherwise, if the HTTP session itself is also trashed and recreated on every single request, then you need to take a step back and look at session cookie and server configuration. Any cause related to a broken HTTP session is at least beyond the context of JSF.
-
You’re using Mojarra 2.1.17 or older, and the view contains EL expressions which bind a view scoped bean property to a tag attribute which is evaluated during view build time. Examples are JSTL
<c:if>
,<c:forEach>
, etc or JSF<ui:include>
,<x:someComponent id="#{...}"
,<x:someComponent binding="#{...}">
, etc. This is caused by a bug in Mojarra (issue 1496). See also Why does @PostConstruct callback fire every time even though bean is @ViewScoped? JSFThis is already fixed in Mojarra version 2.1.18. If you can’t upgrade to a newer version, the workaround is to disable partial state saving as below in
web.xml
, see also JSTL in JSF2 Facelets… makes sense?<context-param> <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name> <param-value>false</param-value> </context-param>
Or when you want to target a specific set of JSF views only:
<context-param> <param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name> <param-value>/foo.xhtml;/bar.xhtml;/folder/baz.xhtml</param-value> </context-param>
Important to mention is that binding the value of JSF component’s
id
orbinding
attribute to a view scoped bean property is a bad practice. Those should really be bound to a request scoped bean property, or an alternative should be sought. See also How does the ‘binding’ attribute work in JSF? When and how should it be used? -
You’re using Mojarra 2.2.0, only that version has a (yet unknown) bug in maintaining the view scope which is already fixed in 2.2.1, see also issue 2916. Solution is to upgrade to a newer version.
-
The
@ViewScoped
annotation is imported from the wrong package. JSF offers two@ViewScoped
annotations, one fromjavax.faces.bean
package for JSF managed beans annotated with@ManagedBean
, and another one fromjavax.faces.view
package for CDI managed beans annotated with@Named
. When the bean scope annotation does not match the bean management annotation, then the actual bean scope will become the bean management framework’s default scope, which is@RequestScoped
in JSF managed beans and@Dependent
in CDI managed beans.You need to ensure that you have either of the following constructs and don’t mix them, see also @ViewScoped bean recreated on every postback request when using JSF 2.2.
import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; @ManagedBean @ViewScoped public class CorrectJSFViewScopedBean implements Serializable {
import javax.inject.Named; import javax.faces.view.ViewScoped; @Named @ViewScoped public class CorrectCDIViewScopedBean implements Serializable {
-
The view is (accidentally?) marked transient via
<f:view transient="true">
. This basically turns on “stateless JSF”, which is new since Mojarra 2.1.19. Hereby the JSF view simply won’t be saved in the JSF state at all and logical consequence is that all referenced view scoped beans can’t be associated with the JSF view anymore. See also What is the usefulness of statelessness in JSF? -
The web application is configured with
com.sun.faces.enableRestoreView11Compatibility
context param set totrue
in an incorrect attempt to “avoid”ViewExpiredException
. With this context param, theViewExpiredException
will never be thrown, but the view (and all associated view scoped beans) will just be recreated from scratch. However, if that happens on every request, then this approach actually hides another problem: the views expire way too soon. This indicates a possible problem in maintaining the JSF view states and/or the HTTP session. How to solve/configure that properly, head to javax.faces.application.ViewExpiredException: View could not be restored. -
The web application’s runtime classpath is polluted with multiple different versioned JSF API or impl related classes. This causes a corruption/mismatch in the identifiers/markers for the JSF view state. You need to make sure you don’t have multiple JSF API JAR files in webapp’s
/WEB-INF/lib
. In case you’re using Maven, make carefully sure that you mark server-provided libraries as<scope>provided</scope>
. See also “Installing JSF” section in our JSF wiki page and the answer to this related question: How to properly install and configure JSF libraries via Maven?. -
When you’re using PrimeFaces
<p:dialog>
, then make sure that the<p:dialog>
has its own<h:form>
and that it is not nested in another<h:form>
. See also p:fileUpload inside p:dialog losing @ViewScoped values. -
When you’re combining PrimeFaces
FileUploadFilter
with PrettyFaces, then make sure that theFileUploadFilter
also runs on PrettyFaces-rewritten/forwarded requests. See also ViewScoped bean rebuilt when FileUploadListener called using PrettyFaces and How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable. -
When you’re using PrettyFaces, a badly configured rewrite rule which redirects CSS/JS/image resources to a JSF page tied to a
@ViewScoped
bean will also give misleading behavior. See also CDI ViewScope & PrettyFaces: Multiple calls to @PostConstruct (JSF 2.2).