I have a problem but do not know exactly for what I should look. I do not think I'm the first one has this problem!
It is a Java SE application with JSF & Co, basic frameworks.
The application can be submitted comments to threads. I write a comment and then I open another thread (another Browser-Tab) so the comment is posted in the newly opened thread.
I have a ManagedBean with the attribute "selectedThread". The error results from the fact that the property is replaced by the newer one. How can I fix this problem?
I have several of ideas, but all produce the same problem.
Thank you!
#ManagedBean
#SessionScoped
public class ViewBean {
private Thread selectedThread = new Thread(); //Current opened Threas
private String threadId=""; //ThreadId read out from Database by Id convert to Object
private Comment selectedThreadComment = new Comment(); //Comment to be made
Working/Failure steps:
Open:thread_detail.xhtml?id=10
ThreadId and selected Trip setted
Write a comment (selectedThreadComment setted)
Open:thread_detail.xhtml?id=11
Commit Comment
Comment is understandably persisted for id 11 instead of id 10.
It does not matter which Scope i use. There must be a way to save the Comment according to which site is opened.
I hope now my problem is better-defined!
It sounds like as if the scope of the managed bean is too broad for the data it holds. The symptoms indicate that the managed bean is been placed in the session scope, while the data it holds is specific to a single HTTP request or a single view. A session scoped managed bean instance lives as long as the browser session is established. It is been shared across all requests/views within the same session. Any change initiated by one window/tab would get reflected in another window/tab in the same session.
You should then be placing the bean in the request or the view scope instead if it holds solely request or view scoped data. If you have some data which should surely be kept in the session scope, e.g. the logged-in user, then you should split the current session scoped managed bean out into two managed beans, each in the right scope. The session scoped one is then to be used to hold the data representing the logged-in user and the request/view scoped one is then to be used to hold the data representing the submitted form data and/or the view state. You can use #ManagedProperty to inject the session scoped one into the request/view scoped one.
See also:
How to choose the right bean scope?
How do servlets work? Instantiation, sessions, shared variables and multithreading (to better understand "under the hoods" working of JSF request/session/application scope)
Related
in a jsf 2.2 application, there is page called test.xhtml that take a paramater called ‘id’ , for example test.xhtml?id=200 . The page is backed by a CDI Session bean named ‘TestBean’. The page has this code to load data:
<f:metadata>
<f:viewAction action="#{testBean.redirectNoParameters}"></f:viewAction>
</f:metadata>
Now based on the id, the application load a set of fields in the session bean with the right values.
public String redirectNoParameters() {
//Code…
//Load fields
test = testDao.find(id);
//Code…
}
Till now is all good.
Except that when the user opens a new tab in the browser and specify a DIFFERENT id, for example test.xhtml?id=300 . the Session bean override the current values of the previous parameter 200, with the new id 300 values.
So my question is how can I use a session bean and deal with many tabs with different parameters? How can I have a session bean for each tab? If this is not possible than what solution do people use for this kind of scenario ? Thanks.
A #SessionScope Bean is living as long as the users Session is active. (hence the name) - It is shared between Requests and Views, which is the "Problem" you are facing.
A #RequestScope Bean will be recreated upon every request (No Matter if first-Access or Ajax-Request), which is possible to use for your usecase (reloading data based on resubmitted IDs), but can be optimized. (This would be a traditional Request/Response-Model as known from PHP - JSF offers a better option)
Your case perfectly matches the #ViewScope. One Bean per View, living as long as the View is present. This would allow you to open an (almost) infinite amount of different Views (hence, the name), each having it's individual set of BackingBeans as long as they are #ViewScope. Multiple "Views" of the same page are possible, each View will maintain the reference to it's dedicated View-Scoped-Beans. (In your example: 2 opened text.xhtml pages and therefore 2 active instances of TestBean, each having its own ID)
The behaviour of your application is correct. Please read the section about Scopes of The Java EE 6 Tutorial.
Your application has created a session scoped bean for the current user and it will be used by all request for such user. Any variable created in such bean will be shared by any tab the user opens.
If you expect the user to interact on multiple tabs with different values for the same variable, consider using a request scoped bean.
First of all, sorry for my english. I have a RequestScoped ManagedBean in order to send parameters to other views, without getting the The scope of the object referenced by expression is shorter than the referring managed beans error. I also have in the same RequestScoped view a p:dataTable showing these beans objects, with an update button for each row, that retrieves this bean to another form in the same view to be update with new values.
The problem is, when I hit the submit button to record the new values, another record is created, instead of the older one being updated. Of course, because the bean is killed when the submit button is pressed (RequestScoped), creating a new bean and another record in the DB. How can I fix it in this scope?
I've seen some alternatives using #PostConstruct here, however I'm not entirely sure it would solve my specific problem.
EDIT:
After researching a bit more into this topic, I came to another doubt: I am using the same Bean in both views (in my case, ProjectBean), should I create a new Bean with RequestScoped annotation (something like ProjectIdBean), set the older one to ViewScoped (so I can reproduce updates naturally on my Database), and let this new Bean handle the requests for other views?
Submit button:
<p:commandButton value="Gravar" action="#{projetoBean.gravar}"
process="#form" update="#form :formTabelaProjetos:tabelaProjetos" />
'Gravar' method:
public void gravar() {
System.out.println("Gravando projeto " + this.projeto.getNome());
ProjetoDAO dao = new ProjetoDAO();
if (this.projeto.getId() == null) {
dao.adiciona(this.projeto);
projetosAtivos = this.getProjetosAtivos();
} else {
dao.atualiza(this.projeto);
}
this.projeto = new Projeto();
}
You can use request scoped backing bean for updating entities. The problem is, that the request life cycle ends when your page is rendered. So anything you loaded will get discarded. The submit creates another request, that will try to reload resources, but it is a different request than the previous one and for example request parameters often do not contain what the programmer expects. But this is what you found out already. There are two ways how to deal with the problem:
1) use simple getters and setters to set "String, Integer" and similar variables in your request scoped bean, that you use to reconstruct and modify the entity you want to update. It is not convenient for the programmer but request scoped beans save resources of your server.
2) change the scope of your backing bean. Session scope is not ideal, because it can stay in memory for a really long time. And you might realize you need to clean it up manually. Much better is ViewScoped bean as it allows you to work with the entities you loaded over several steps. It gets wiped out when the user leaves the page.
#javax.faces.bean.ViewScoped
#javax.faces.bean.ManagedBean
public class SomethingBean {
......
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to choose the right bean scope?
I'm newbie in JSF programming, and I need a clarification about bean scopes. I have already read all the questions about this argument, but is not so clear.
I don't understand the request scope well. I understand that: "This is the default scope and basically the bean is alive throughout a single HTTP request."
So for example, suppose that we ask the browser to open a web page with a form. When we make the request, a request scope bean is created, the life-cycle begins and after the render response phase, the Java bean is destroyed.
Then we fill out the form and we press a button. This will start another HTTP request, right?
In the same context, if a have a view scope bean instead of a request scope bean, what is the difference? How many bean instances are created? Why is it better to use this with a datatable?
The request scope as all your sources including the post linked by BalusC say starts living a short while after your request hits the server, and is destroyed shortly after the last bit of the response has been send back.
Indeed, if you postback a form a new request starts and thus a new request scope. This means everything that is request scoped will be created again. So for a form that is first rendered, and then posted back once, 2 request scoped beans will be created.
The view scope lives as long as you do postbacks to the same view (page). This works by means of the hidden form parameter called javax.faces.ViewState. The value of this is an entry into some kind of logical Map if you use save state on server. How a JSF implementation actually resolves this is not that important here (but yes, it's mostly just a Map).
After the postback JSF is able to retrieve the exact same view scoped beans again by means of this parameter. So for a form that is first rendered, and then posted back once, 1 view scoped bean will be created.
For a datatable you will almost always want to use the view scope. The reason is that you want the data to be the same before and after a postback. If your data is 100% static and/or you don't have postbacks (your table is not in a form), you can use the request scope instead.
I have a session scoped managed bean, with a property current. If I have a method
public void resetCurrent() {
current = new Configuration();
}
in the bean, it gets called automatically every time I navigate to a new page in the application. Is this normal behavior? I am not calling the method anywhere in the code.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Thank you.
JSF doesn't do that. It's your code which does that. Your view or another bean or maybe the bean itself is calling it. Putting a debug breakpoint on that line or adding Thread.dumpStack() should give you insights in who's calling it by reading the call stack. Or just rename the method to something else and check if you don't see compilation errors during build or get EL exceptions during runtime which should pinpoint the callers.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Depends on the functional requirements. For example, if the bean is supposed to hold view scoped data, then put it in the view scope instead. Or if it is supposed to hold session scoped data (e.g. logged-in user) and you're basically logging out, then rather invalidate the session.
I have three screens(views) associated with separate managed beans for each view.
And, I have a common pop-up dialog which can be opened in all the views.
Can I define a managedbean separately for the pop-up with state #NoneScoped; and maintain an instance of it in each parent bean?? or
Do I need to maintain pop-up data in all three parent views?
Please, suggest me the best practice.
I think this is what you are looking for (check out the answer by BalusC) -
Whats the correct way to create multiple instances of managed beans in JSF 2.0
And since you are using #NoneScoped (unlike #RequestScoped in the above question), I also recommend you to look at this answer by BalusC (about #NoneScoped) -
what is none scope bean and when to use it?
And according to this answer, you can't maintain any instances of a managedbean that is none-scoped, as they are garbaged as soon as they are used.
So, in your case since you have three separate views, for each view, the bean is constructed and used to build the view and garbaged. (Looks like it does not even last for a request cycle). When you request another view, it will be a separate instance.
To have multiple intances of a bean, you can have three properties in a Session-Scoped been (to make them survive across multiple views).
#ManagedBean
#SessionScoped
public class Parent {
private Child child1;
private Child child2;
private Child child3;
// ...
}