JSF bean action method return string test - jsf

I tried to understand from this question the difference between returning null and "" in JSF action, but couldn't experience in real.
Below is the quote form the OP
From what I understand, when a JSF action returns "" (empty String)
the user stays on the current page but the view is refreshed. However,
when the action returns null the user still stays on the current page
but the old view is reused
I am in a confusion of understanding the difference between returning "", null and "viewid?faces-redirect=true" from a JSF Backing bean. I tried to understand the difference with a small example, but I couldn't experience the actual difference. Below are the code snippets of my example.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>Jsf Questions</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jspx</param-value>
</context-param>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/jsfintroapp/*</url-pattern>
</servlet-mapping>
</web-app>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<managed-bean>
<managed-bean-name>userLogin</managed-bean-name>
<managed-bean-class>com.srk.beans.UserLogin</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<description>Contains list of all navigation rules here</description>
<from-view-id>/*</from-view-id>
<navigation-case>
<display-name>WELCOME</display-name>
<from-outcome>welcome</from-outcome>
<to-view-id>/geek_examples/authorized_user.jspx</to-view-id>
</navigation-case>
</faces-config>
My managed bean is a request scoped bean, as declared above.
UserLogin.java (Backing bean) code snippet
public String saveData() {
//String returnString = "";//Case 1 : works - user stays on the same page
//String returnString = null;//Case 2: works - user stays on the same page
// Case 3:
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
LOG.debug("view id = "+ viewId);
String returnString = "?faces-redirect=true";//viewId+
LOG.debug("return string = "+ returnString);
LOG.debug("Username = "+ getName() + " password = "+ getPassword());
return returnString;
}
login.jspx
<html 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">
<f:view>
<head>
<title>JSF Question</title>
</head>
<body>
<h:form>
<h3>User Name and Password</h3>
<table>
<tr>
<td><h:outputLabel value="Name"/></td>
<td><h:inputText value="#{userLogin.name}"/></td>
</tr>
<tr>
<td><h:outputLabel value="Password"/></td>
<td><h:inputText value="#{userLogin.password}"/></td>
</tr>
<tr>
<td><h:commandButton value="Sign In" action="#{userLogin.saveData}"/></td>
</tr>
</table>
</h:form>
</body>
</f:view>
</html>
Libraries used in this example
I tried to access the login.jspx page, entered values in the fields of form and clicked on Sign In. I can always see the same page, no matter what I return there in my saveData() method which is not showing any difference in behavior, Can somebody throw some light with respect to this concept?

As answered in that answer, returning null or void will reuse the same JSF view, including all view scoped beans attached to it.
JSF 1.2, however, has no concept of a "view scoped bean". This was introduced in JSF 2.0. Moreover, you've a request scoped bean. It'll always be recreated on every request, regardless of how you navigate. So it's not really noticeable by looking at how the bean behaves. It's only noticeable if you manually mimic the JSF 2.0 view scope by putting an attribute in the UIViewRoot and then checking in the constructor of the request scoped bean if it's still present.
If you have used a JSF 2.x view scoped bean, you'd have noticed that it's recreated (i.e. it's (post)constructor is invoked again) when you navigate using a non-null outcome. See also a.o. How to choose the right bean scope?
And, the ?faces-redirect=true query string is also JSF 2.x specific and not recognized by JSF 1.x. In JSF 1.x, to achieve the same effect, either add <redirect/> to the <navigation-case>, or use ExternalContext#redirect().
public void saveData() throws IOException {
// ...
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
String url = ec.getRequestContextPath() + "/login.jsf";
ec.redirect(url);
}
Which navigation approach to choose is elaborated in this related question: How to navigate in JSF? How to make URL reflect current page (and not previous one). Generally, in UX and SEO perspective, using POST for page-to-page navigation is bad practice. Always use GET for that or perform a redirect after POST.
In any case, when developing with JSF 1.x, you should not be looking at JSF 2.x targeted answers/resources. It'll only lead to confusion because many things are done differently (better!) in JSF 2.x. JSF 2.x exist more than 5 years already and JSF 1.x was EOL for nearly as long. It doesn't make sense to keep working on dead technology. Consider migrating.

Related

JSF Memory leak: bean not destroyed on refresh / redirect on same page

I use JSF viewscope for my managedbean.
I call the managed bean in a html view.
When the page is refresh, there is a new managed bean allowed and the old one stay in the memory.
If I refresh and refresh and refresh... I have got a huge number of the managed beans in the memory.
I try to run garbage collector, nothing append.
The managed beans stay until the session expired. At the end of session, by user action or timeout, the managed bean are freed.
I only have this problem when I stay on the same page (refresh on the browser -F5- or redirection link without JSP tag or java code redirection).
When I change page, there is only one managed bean freed (the last one). The others stay in the memory.
It seme to work with JSP tag, the managed bean are freed after the redirection.
Second Bug :
Some time I arrived in strange case :
I have some managed bean not freed in memory, I use JSP tag redirect (may 3/4 times) and the system do Predestroy / PostConstruct / Predestroy...
And after that every redirection do PostConstruct / Predestroy for not JSP tag or java redirection, Predestroy / PostConstruct / Predestroy for JSP tag.
In the memory a managed bean not freed is freed after that.
I realy don't know what is realy the case reproduce this, but it do multiple time.
Do somebody have some solution for this problems ?
I see a post look like problem here and I report a bug on java.net
Configuration :
Java EE 7 / glassfish 4
AViewscope.java :
package com.btm.viewscopetest;
import java.io.IOException;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
#ManagedBean
#ViewScoped
public class AViewscope implements Serializable {
#PostConstruct
public void postConstruct() {
System.out.println("PostConstruct");
}
#PreDestroy
public void preDestroy() {
System.out.println("PreDestroy");
}
public AViewscope() {
}
public String getSomething() {
return "Something";
}
public void redirect() throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.redirect("apage.xhtml");
}
}
apage.xhtml :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<head>
<title>A page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<h:form>
<h:outputText value="Get something: #{aViewscope.something}" />
<br/>
<br/>
<h:commandButton value="Stay on this page with java " actionListener="#{aViewscope.redirect}"/>
<br/>
<h:commandButton value="Stay on this page with direct link" action="apage" />
<br/>
<h:commandButton value="Go to another page" action="anotherPage"/>
<br/>
<h:commandLink value="Stay on this page with direct link h tag " action="apage.xhtml" />
Stay on this page with direct link a tag
</h:form>
</body>
</html>
anotherPage.xhtml :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<head>
<title>Another Page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<h:form>
<h:commandButton value="Go to another page" action="apage"/>
</h:form>
</body>
</html>
web.xml :
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
I have got a huge number of the managed beans in the memory.
I try to run garbage collector, nothing append
This is not a bug, it's intentional. JSF maintains a certain number of beans in the memory, if your javax.faces.STATE_SAVING_METHOD is set to server in the web.xml. The client will now always submit a javax.faces.ViewState (id), allowing the server to identify the proper beans to load.
You can limit the amount of views stored per session, by setting the context-param com.sun.faces.numberOfViewsInSession to a number that matches your needs.
But be aware that if you choose 1, and the user use backwards navigation he will encounter ViewExpired exceptions if the bean has been removed.
Another option to decrease memory load would be to handle the view-storage over to the client, by setting javax.faces.STATE_SAVING_METHOD to client. However this will lead to increased network traffic, because now the client does not only need to have a javax.faces.ViewState to track - but the whole view itself. I'm not one hundred percent sure how exactly the client-option works, but to me it feels dangerous to let a client keep track of the "View" rather than just the identifier.

Why is it defined this way in web.xml in JSF?

In this little project, there is only one class RichBean.java, and a JSF file index.html, to demonstrate the use of CDI in JSF. My question is regarding the "
<welcome-file>faces/index.xhtml</welcome-file>"
defined in web.xml. Why is it "faces/"?
There is no any mentioning of "faces/" directory or configuration. I thought "faces" is just a name that can be anything, but it isn't the case. I tried changing it to something else, i.e. "faceg", it then doesn't work.
RichBean.java
#Named
#SessionScoped
public class RichBean implements Serializable {
private String name;
#PostConstruct
public void postContruct() {
name = "John";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
index.xhtml
....
<body>
<ui:composition template="/templates/template.xhtml">
<ui:define name="title">Hello world JSF</ui:define>
<ui:define name="body">
<fieldset style="width:500px">
<legend>Helloworld using JSF and RichFaces</legend>
<p>
This example demonstrates adding ajax processing and updating to a standard JSF component.
</p>
<rich:panel header="Ajax enabled inputText">
<h:form id="helloWorldJsf">
<h:outputLabel value="Name:" for="nameInput"/>
<h:inputText id="nameInput" value="#{richBean.name}">
<a4j:ajax event="keyup" render="output"/>
</h:inputText>
<h:panelGroup id="output">
<h:outputText value="Hello #{richBean.name}!"
rendered="#{not empty richBean.name}"/>
</h:panelGroup>
</h:form>
</rich:panel>
</fieldset>
</ui:define>
</ui:composition>
</body>
</html>
beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
web.xml.
How is "faces/" configured? I have no idea of how and why it's connected to anything else in the proejct.
I am learning this demo. Please help understand this. Thanks a lot.
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web- app_3_0.xsd">
<!-- add a welcome-file-list entry to allow JSF pages to be used as welcome files -->
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
The Servlet class FacesServlet starts the JSF request processing
life cycle and must be defined in the web.xml. The servlet mapping
tag defines the for which URL the FacesServlet should be executed.
The pattern /faces/* is commonly used by the JSF specification but
any other prefix or extension is possible. The example uses as
web-app attribute version=“2.5” this means we are using
servlet-api version 2.5. If you use tomcat 6 we need minimum
servlet-api in version 2.5. Compared with jsf 1.2 nothing changed in
this example.
Below you can see the web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<display-name>HelloWorld with JSF RI 2 (Beta 2)</display-name>
<servlet>
<display-name>FacesServlet</display-name>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
</web-app>
You can change /faces/ to /facesg/ as per your requirement and it will work for you.
I hope it will resolve your query !!

<h:button> not executing simple bean method

im trying to do a simple bean method, but it does not work, dont show the syso in the console of eclispe, and when i click the button, it change my url to http://localhost:8080/Projeto01/index.jsf?jftfdi=&jffi=%2Findex.xhtml
why dont work and why it change the url for this strange url ?
my msg.java(bean)
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Msg {
public void show() {
System.out.println("Working Bean Method");
}
}
my index.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<h:head></h:head>
<h:body>
<h:form>
<h:button value="Show" action="#{msg.show()}"></h:button>
</h:form>
</h:body>
</ui:composition>
</html>
and my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>do0</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>
The <h:button> is a simple page-to-page navigation button. As you can see in the tag documentation, it doesn't support the action attribute at all. You're most likely confusing the <h:button> with <h:commandButton> which in turn supports that attribute.
In order to achieve your functional requirement of invoking a JSF backing bean method on press of a button, just replace <h:button> by <h:commandButton>:
<h:commandButton value="Show" action="#{msg.show()}" />
See also:
Difference between h:button and h:commandButton
As to those jftfdi and jffi query string parameters in the target URL, this is a bug in Mojarra's implementation of the new JSF 2.2 flow scope. This is fixed in Mojarra 2.2.5. Note that this is further unrelated to your concrete problem as you shouldn't be using a <h:button> in first place.
See also:
How to disable jftfdi jffi query params in JSF

JSF do not execute the bean

im trying to learn JSF, but something i lost, cuz this button is not showing the message in eclipse console
the JAVA BEAN:
package beans;
public class protocoloBean {
public void incluirProtocolo() {
System.out.println("MSG");
}
}
the xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h:button value="Protocolar"
action="#{protocoloBean.incluirProtocolo()}"></h:button>
</h:body>
</html>
and the faces-config:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<managed-bean>
<managed-bean-name>protocoloBean</managed-bean-name>
<managed-bean-class>beans.protocoloBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<application/>
</faces-config>
what im doing wrong ? or i lost :(
Your JSF code is wrong. You're trying to fire an action using <h:button> when you need/want to use <h:commandButton>. <h:button> is intended for navigation purposes only. See here for a difference between them: Difference between h:button and h:commandButton
You should update your code to:
<h:body>
<ui:remove>
<h:button value="Protocolar"
action="#{protocoloBean.incluirProtocolo()}"></h:button>
</ui:remove>
<!--
Note that h:commandButton MUST ALWAYS be inside a h:form
Otherwise, the action won't fire
-->
<h:form>
<h:commandButton value="Protocolar"
action="#{protocoloBean.incluirProtocolo}" />
</h:form>
</h:body>
After updating your code, the log message will be printed as expected.
Since you're learning JSF 2.2, I would suggest start using JSF 2 features like barely using the faces-config.xml file for managed bean definitions. You could improve your code to this:
#ManagedBean
#SessionScoped
public class ProtocoloBean {
public void incluirProtocolo() {
System.out.println("MSG");
}
}
And your faces-config.xml file*:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
</faces-config>
* Yes, it is empty :).
Since you're new to JSF, I would recommend start declaring your beans as #RequestScoped or #ViewScoped instead of #SessionScoped. You cn read more info about this here: How to choose the right bean scope?
two mistakes in your code:
the first character of your class name should be Captialized. You should use "ProtocoloBean" insteads of "protocoloBean"
Action attribute is used for redirect page, the method type must be String instead of void. If you just want to execute some code, then you should use "actionListener" rather than "action", in this case your method return type can be void, but make sure (ActionEvent action) is defined as your method input argument

#SessionScoped bean injected as #ManagedProperty of a #ViewScoped acts like #RequestScoped in MyFaces, works fine in Mojarra

Here is my simple example:
Index.xhtml in root:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Title</title>
</h:head>
<h:body>
<h:form>
<h:inputText value="#{index.variable}"></h:inputText>
<h:commandButton action="#{index.submit()}" type="submit"></h:commandButton>
</h:form>
</h:body>
</html>
Its ManagedBean:
import java.io.IOException;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
#ManagedBean
#ViewScoped
public class Index implements Serializable {
#ManagedProperty("#{sessionBean}")
private SessionBean sessionBean; /*getter&setter*/
private String variable; /*getter&setter*/
public void submit() {
sessionBean.setAsd(variable);
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
try {
context.redirect("next");
} catch (IOException ex) {
}
}
}
/next/index.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Check variable</title>
</h:head>
<h:body>
#{sessionBean.asd}
</h:body>
</html>
SessionBean.java:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class SessionBean implements Serializable {
private String asd;
public String getAsd() {
return asd;
}
public void setAsd(String asd) {
this.asd = asd;
}
}
If I use mojarra implementation everything works as expected: after form submitting, user gets redirected to root/ and see the value that was printed in the form of index.xhtml.
But if I use myfaces, asd becomes null right after existing form gets submitted. SessionScoped bean acts like RequestScoped
Why?
here is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
<!--listener-class>com.sun.faces.config.ConfigureListener</listener-class-->
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
Server: Apache Tomcat 7.0.34
UPDATE: it works if we change the ViewScoped annotation of Index.java bean to RequestScoped or SessionScoped. But why?
I currently have a JSF 2.1 project written with the help of Mojarra. Just for experimenting, I changed the implementation to MyFaces and ran the application only to see issues similar to yours (all my injected #ManagedProperty variables end up null after a POST submit). I switched back to Mojarra and the app runs fine. So, basically something is different in the MyFaces implementation.
A bit of googling led me to this unresolved issue - MYFACES-3656. Here's an excerpt from the issue reporter on how to fix the issue:
If you set the org.apache.myfaces.SERIALIZE_STATE_IN_SESSION to false
and redeploy the application then everything works as expected.
How does this help? The answer is in the comments section:
I think the behavior described is expected (different to say that the
behavior described is desired or intentionally done in that way).
What's happening here is in MyFaces serialization is set to true by
default (some old lines from JSF 1.0 spec says so, even if RI does not
implement it in this way). In JSF 2.2 spec, SERIALIZE_STATE_IN_SESSION
param will be standardized and set to false by default.
Serialization causes that all beans under view scope are in fact
"recreated". If the param is set to false, the beans are stored into
session and on further requests are used, looking like everything is
ok, but that fact is not true because in a cluster configuration the
same application will fail.
Only the first time the view scope bean is created, the references
from managed-property takes effect, but if the bean is
serialized/deserialized, the references are not restored back, because
on the serialization step, even the application and session scope
beans are serialized too.
.....
How to solve it? I haven't found a decent solution to this issue. One
could think on just restore the view scope bean and reapply
#ManagedProperty annotations or entries found in faces-config.xml, but
the problem is the view scope bean still is storing information that
shouldn't be there from start (only marking the fields as transient
will do the trick). It is possible define an special mode were this
hack or some variant is done, but it will be only in myfaces and it
cannot be enabled by default.
Similar issue has been reported and replied with the above explanation in this mailing-list archive
Now, since in your case you are not explicitly setting a STATE_SAVING_METHOD, it defaults to server. Consequently, SERIALIZE_STATE_IN_SESSION comes into effect and defaults to true.
I tried your code with MyFaces on Tomcat and set SERIALIZE_STATE_IN_SESSION to false and it works. However, in the event, you set the STATE_SAVING_METHOD to client, nothing will work and you'll get a view state not found error.

Resources