I've got two instances of a SessionScoped CDI bean for the same session. I was under the impression that there would be one instance generated for me by CDI, but it generated two. Am I misunderstanding how CDI works, or did I find a bug?
Here is the bean code:
package org.mycompany.myproject.session;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
#Named #SessionScoped public class MyBean implements Serializable {
private String myField = null;
public MyBean() {
System.out.println("MyBean constructor called");
FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)fc.getExternalContext().getSession(false);
String sessionId = session.getId();
System.out.println("Session ID: " + sessionId);
}
public String getMyField() {
return myField;
}
public void setMyField(String myField) {
this.myField = myField;
}
}
Here is the Facelet code:
<?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"
xmlns:f="http://java.sun.com/jsf/core">
<f:view contentType="text/html" encoding="UTF-8">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:form id="form">
<h:inputText value="#{myBean.myField}"/>
<h:commandButton value="Submit"/>
</h:form>
</h:body>
</f:view>
</html>
Here is the output from deployment and navigating to page:
INFO: Loading application org.mycompany_myproject_war_1.0-SNAPSHOT at /myproject
INFO: org.mycompany_myproject_war_1.0-SNAPSHOT was successfully deployed in 8,237 milliseconds.
INFO: MyBean constructor called
INFO: Session ID: 175355b0e10fe1d0778238bf4634
INFO: MyBean constructor called
INFO: Session ID: 175355b0e10fe1d0778238bf4634
Using GlassFish 3.0.1
Ryan, as covener already wrote, the constructor will also get called for each and every proxy for that bean. This is a standard behaviour of all proxy mechanisms which provide not only interface-proxying (like java.lang.reflect.proxy stuff) but real class-proxying.
Also imagine that the ct will also be called for each and every serialization. So if you work on a heavily load balanced cluster, you will see this lots of times. So please use #PostConstruct for beans in general.
LieGrue,
strub
It's likely that your CDI implementation calls the underlying beans default constructor when newing up proxies to use for injection points -- this is the default behavior of javassist which is used in weld and openwebbeans.
Avoid heavy lifting in your default constructor, moving it into #PostConstruct if you can!
Related
Environment:
I have an EAR application with WildFly 10.0.0.Final. It has one module for the web application which is based on JSF Mojarra 2.2.12-jbossorg-2 20150729-1131 (using PrimeFaces 6 for the UI and Omnifaces 2.5.1 for additional utilities).
Use Case:
My Problem is around view expiration. I simplified my app to a small bean/view showcase which contains the problem. The use case is pretty simple: if the view is expired and the user triggers some action, he should be redirected to the view expired page. I am using the Omnifaces FullAjaxExceptionHandler for this.
Problem:
The redirect on view expiration is working in nearly all cases. But it is not working anymore as soon as I use the JSTL tag <c:forEach/> in my view. Then, the HTTP Request simply has a Status (failed) in my Chrome Dev Tools and nothing happens.
The following Bean/View combination shows the problem:
View: text.xhtml
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head id="head">
<title>Test</title>
</h:head>
<h:body>
<h:form>
<p:commandButton action="#{TestBean.throwError()}" value="Throw" update=":test"/>
</h:form>
<h:panelGroup id="test">
Test
</h:panelGroup>
<c:forEach items="#{TestBean.list}" var="item">
#{item.toString()}
</c:forEach>
<p>
<input type="button" value="Invalidate session"
onclick="$.get('#{request.contextPath}/invalidatesession?#{now.time}', alert('Session invalidated!'))"/>
</p>
</h:body>
</html>
Bean: Test.java
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#ViewScoped
#Named(value = "TestBean")
public class Test implements Serializable
{
private static final long serialVersionUID = -6513676596620667863L;
private List<String> list = new ArrayList<>();
#PostConstruct
public void init()
{
this.list.add("aaaaa");
this.list.add("bbbbb");
this.list.add("ccccc");
}
public void throwError()
{
throw new IllegalArgumentException("bla");
}
public List<String> getList()
{
return this.list;
}
}
It's pretty much the FullAjaxExceptionHandler Show Case of Omnifaces with the JSTL tag <c:forEach/>. As soon as I remove it from my View, everyhting works fine.
How to define the max number of component trees in client mode? How to prevent calling #PostConstruct method?
I'm developing an application by JavaEE7 with glassfish 4.1.
If I remember correctly, when javax.faces.STATE_SAVING_METHOD is client, there is no limit of component tree.
But when I opened more than 25 tabs in Chrome and operate the first tab, that tab's managed bean will construct and call #PostConstruct method.
I think this behavior seems losing component tree to me.
The following is source code of my application.
test.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">
<ui:composition
template="/template/template.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"
>
<h:panelGrid columns="5" cellpadding="5" >
<p:commandButton id="returnButton" value="return"
action="#{testEditBean.return()}"
immediate="true"
/>
</h:panelGrid>
</ui:composition>
testBean.java
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named(value = "testBean")
#ViewScoped
public class TestBean implements Serializable {
#PostConstruct
public void index() {
}
public String doReturn() {
String ret = "/content/tmp/testSearch.xhtml";
return ret;
}
}
[postscript 2016/01/28]
I understand that a HTTP session stored view scoped beans (max 25) and view state only stored component tree.
This is my new question.
Unless we change mojjara 2.x to another JSF implementation, we couldn't open more than 25tabs?
"more than 25 tabs" contains this case that "an user open 2 tabs, and 23 transition occur in 2nd tab."
I'm having an issue similar to this post and the answer from #BalusC with 3 solutions but:
I'm not using of the mentioned EL expressions
I don't want to go with the second solution (it's complex enough for me like this)
and partial state saving is set to false.
My code is as follows:
index.xhtml:
<?xml version="1.0" encoding="windows-1256" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Insert title here</title>
</h:head>
<h:body>
<h:form>
<p:panelMenu id="westMenu">
<p:submenu id="sub1" label="System Monitor">
<p:menuitem id="menu1" value="live monitoring"
action="#{menusBean.activateMenu('sub1_menu1')}"
update=":centerPane,westMenu"
disabled="#{menusBean.active['sub1_menu1']}" />
<p:menuitem id="menu2" value="reports"
action="#{menusBean.activateMenu('sub1_menu2')}"
update=":centerPane,westMenu"
disabled="#{menusBean.active['sub1_menu2']}" />
</p:submenu>
<p:submenu id="sub2" label="Charging System Nodes" />
<p:submenu id="sub3" label="Additional Nodes" />
</p:panelMenu>
</h:form>
<h:panelGroup id="centerPane">
...
</h:panelGroup>
</h:body>
</html>
MenusBean.java:
package menus;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.view.ViewScoped;
#ManagedBean
#ViewScoped
public class MenusBean implements Serializable{
private static final long serialVersionUID = -7793281454064343472L;
private String mainPage="sub1_menu1";
private Map<String, Boolean> active;
public MenusBean(){
System.out.println("MenusBean created");
active = new HashMap<>();
active.put(mainPage, true);
active.put("sub1_menu2", false);
}
public boolean activateMenu(String page){
active.put(mainPage, false);
active.put(page, true);
mainPage = page;
for (Map.Entry<String, Boolean> e : active.entrySet())
System.out.println(e.getKey()+":"+e.getValue());
return true;
}
public Map<String, Boolean> getActive() {
return active;
}
}
When executed, I get:
MenusBean created
MenusBean created
MenusBean created
How is this caused and how can I solve it?
This,
import javax.faces.view.ViewScoped;
is the JSF 2.2-introduced CDI-specific annotation, intented to be used in combination with CDI-specific bean management annotation #Named.
However, you're using the JSF-specific bean management annotation #ManagedBean.
import javax.faces.bean.ManagedBean;
You should then be using any of the scopes provided by the very same javax.faces.bean package instead. The right #ViewScoped is over there:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MenusBean implements Serializable{
If you use the wrong combination, the bean behaves as a #RequestScoped bean and be recreated on each call.
Alternatively, if your environment supports CDI (GlassFish/JBoss/TomEE with Weld, OpenWebBeans, etc), then you could also replace #ManagedBean by #Named:
import javax.inject.Named;
import javax.faces.view.ViewScoped;
#Named
#ViewScoped
public class MenusBean implements Serializable{
It's recommended to move to CDI. The JSF-specific bean management annotations are candidate for deprecation in future JSF / Java EE versions as everything is slowly moving/unifying towards CDI.
I'm having an issue similar to this post and the answer from #BalusC with 3 solutions but:
I'm not using of the mentioned EL expressions
I don't want to go with the second solution (it's complex enough for me like this)
and partial state saving is set to false.
My code is as follows:
index.xhtml:
<?xml version="1.0" encoding="windows-1256" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Insert title here</title>
</h:head>
<h:body>
<h:form>
<p:panelMenu id="westMenu">
<p:submenu id="sub1" label="System Monitor">
<p:menuitem id="menu1" value="live monitoring"
action="#{menusBean.activateMenu('sub1_menu1')}"
update=":centerPane,westMenu"
disabled="#{menusBean.active['sub1_menu1']}" />
<p:menuitem id="menu2" value="reports"
action="#{menusBean.activateMenu('sub1_menu2')}"
update=":centerPane,westMenu"
disabled="#{menusBean.active['sub1_menu2']}" />
</p:submenu>
<p:submenu id="sub2" label="Charging System Nodes" />
<p:submenu id="sub3" label="Additional Nodes" />
</p:panelMenu>
</h:form>
<h:panelGroup id="centerPane">
...
</h:panelGroup>
</h:body>
</html>
MenusBean.java:
package menus;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.view.ViewScoped;
#ManagedBean
#ViewScoped
public class MenusBean implements Serializable{
private static final long serialVersionUID = -7793281454064343472L;
private String mainPage="sub1_menu1";
private Map<String, Boolean> active;
public MenusBean(){
System.out.println("MenusBean created");
active = new HashMap<>();
active.put(mainPage, true);
active.put("sub1_menu2", false);
}
public boolean activateMenu(String page){
active.put(mainPage, false);
active.put(page, true);
mainPage = page;
for (Map.Entry<String, Boolean> e : active.entrySet())
System.out.println(e.getKey()+":"+e.getValue());
return true;
}
public Map<String, Boolean> getActive() {
return active;
}
}
When executed, I get:
MenusBean created
MenusBean created
MenusBean created
How is this caused and how can I solve it?
This,
import javax.faces.view.ViewScoped;
is the JSF 2.2-introduced CDI-specific annotation, intented to be used in combination with CDI-specific bean management annotation #Named.
However, you're using the JSF-specific bean management annotation #ManagedBean.
import javax.faces.bean.ManagedBean;
You should then be using any of the scopes provided by the very same javax.faces.bean package instead. The right #ViewScoped is over there:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MenusBean implements Serializable{
If you use the wrong combination, the bean behaves as a #RequestScoped bean and be recreated on each call.
Alternatively, if your environment supports CDI (GlassFish/JBoss/TomEE with Weld, OpenWebBeans, etc), then you could also replace #ManagedBean by #Named:
import javax.inject.Named;
import javax.faces.view.ViewScoped;
#Named
#ViewScoped
public class MenusBean implements Serializable{
It's recommended to move to CDI. The JSF-specific bean management annotations are candidate for deprecation in future JSF / Java EE versions as everything is slowly moving/unifying towards CDI.
I'm wondering if I'm having the same findings but after creating a javaee6 web project generated from jboss maven archetype I have the following result.
f:viewParam, did not work on dependent or view scope only in request scope.
public class BaseBean {
protected boolean edit;
public boolean isEdit() {
System.out.println("get edit=" + edit);
return edit;
}
public void setEdit(boolean edit) {
System.out.println("set edit=" + edit);
this.edit = edit;
}
}
#Named
#RequestScoped
public class RequestBean extends BaseBean { }
#Named
public class DependentBean extends BaseBean { }
#Named
#ViewScoped
public class ViewBean extends BaseBean { }
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
template="/WEB-INF/templates/default.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="edit" value="#{dependentBean.edit}" />
</f:metadata>
</ui:define>
<ui:define name="content">
<h:outputText value="#{dependentBean.edit}"></h:outputText>
</ui:define>
</ui:composition>
For the request and view scope views, it's almost the same as the one above except for the manage bean used.
Any idea?
The problem is that you're mixing JSF annotations from package javax.faces.bean with CDI annotations (noticed by the usage of #Named) from package javax.enterprise.context and they can't be used altogether for being handled by different managers (JSF and CDI managers). In your application, your managed beans should be from JSF or from CDI, not from a mix of both.
Note that CDI doesn't support #ViewScoped yet, this scope is available only for JSF. More info: CDI missing #ViewScoped and #FlashScoped