My CDI-managed @Named bean's postConstruct method is being invoked multiple times per view on page refresh in browser. However, @PreDestroy is never called.
@Postconstruct method called multiple times in a CDI-managed @Viewscoped bean is an old problem with many suggestions how to solve this issue. Many of them can be found here on Stack Overflow. I've tried all of them, but none of them helped.
I have even created a simple project with just one single bean to help everyone reproduce the problem. It can be found on GitHub.
I've tried
- Checked JSF implementation version Mojarra 2.2.12
- Checked WELD version (2.3.2)
- Checked annotations (both annotations are from CDI package)
- Deploy to different Application servers (Wildfly 9, WildFly 10, Payara 4.1.1.161_1) - nothing worked.
- Checked the XHTML page for and bindings. Did not work.
- javax.faces.PARTIAL_STATE_SAVING - again, did not work.
- There is no ViewExpired exception
- There are no other jars in the classpath (included in the WAR). There is just a provided JEE-7 dependency. The WAR itself only has 2,6 kB.
- Prettyfaces or any other framework are used (see previous bullet).
The CDI-Managed bean looks like this:
package com.viewscopetest;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.faces.view.ViewScoped;
import java.io.Serializable;
@Named
@ViewScoped
public class TestViewBean implements Serializable {
private String hello;
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
@PostConstruct
private void postConstruct() {
hello = "Hello";
System.out.println("Again");
}
}
The view looks like this:
<?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://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:form id="test">
<h:outputLabel value="#{testViewBean.hello}"/>
</h:form>
</html>
There is an near-empty faces-config.xml
<?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>
And a very basic web.xml
<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">
<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>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
Finally, a very basic beans.xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans
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/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
All those configuration files are stored in WEB-INF folder (beans.xml, faces-config.xml, web.xml).
Nothing else is really present in the folder. Here are some informations about the environment (taken from WildFly 9 log).
[2016-05-07 12:29:46,379] Artifact Gradle : com.test : viewscopetest-0.1.war: Artifact is being deployed, please wait...
12:29:46,532 INFO [org.jboss.as.server.deployment] (MSC service thread 1-7) WFLYSRV0027: Starting deployment of "viewscopetest-0.1.war" (runtime-name: "viewscopetest-0.1.war")
12:29:46,825 INFO [org.jboss.weld.deployer] (MSC service thread 1-5) WFLYWELD0003: Processing weld deployment viewscopetest-0.1.war
12:29:46,871 INFO [org.hibernate.validator.internal.util.Version] (MSC service thread 1-5) HV000001: Hibernate Validator 5.2.3.Final
12:29:47,003 INFO [org.jboss.weld.deployer] (MSC service thread 1-6) WFLYWELD0006: Starting Services for CDI deployment: viewscopetest-0.1.war
12:29:47,029 INFO [org.jboss.weld.Version] (MSC service thread 1-6) WELD-000900: 2.3.2 (Final)
12:29:47,078 INFO [org.jboss.weld.deployer] (MSC service thread 1-3) WFLYWELD0009: Starting weld service for deployment viewscopetest-0.1.war
12:29:47,766 INFO [javax.enterprise.resource.webcontainer.jsf.config] (ServerService Thread Pool -- 58) Initializing Mojarra 2.2.12-jbossorg-2 20150729-1131 for context '/viewscopetest-0.1'
12:29:48,085 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 58) WFLYUT0021: Registered web context: /viewscopetest-0.1
12:29:48,099 INFO [org.jboss.as.server] (management-handler-thread - 2) WFLYSRV0010: Deployed "viewscopetest-0.1.war" (runtime-name : "viewscopetest-0.1.war")
[2016-05-07 12:29:48,113] Artifact Gradle : com.test : viewscopetest-0.1.war: Artifact is deployed successfully
[2016-05-07 12:29:48,113] Artifact Gradle : com.test : viewscopetest-0.1.war: Deploy took 1 735 milliseconds
The problem is, the @VieScoped bean behaves like a request-scoped one. On page refresh, I'd expect the bean to be reused, instead of re-creating it and calling @PostConstruct method again.