ViewScope constructor called twice, not sure why

2019-03-16 18:28发布

问题:

I've seen the other questions regarding calling a bean constructor and ViewScope, and I'm still having difficulty. The problem I'm seeing involves two specific pages in my application. The first is a dataTable (for now it is filled with randomly generated data but will eventually call a database), the second page is a fairly simple display page in which information from the selected row is displayed in a form for either editing or viewing - this is my detail.xhtml page. It is the bean for this page that is the issue; its constructor is called twice: first when I navigate to the page, again when I press the commandButton whether to submit changes or cancel changes does not matter, the detail.xhtml backing bean's constructor is called a second time.

My bean is @ViewScoped, importing javax.faces.bean.ViewScoped. A few other details that might make a difference, but if they do I don't understand why: my UserDetailBean.java inherits from a base bean (which I so originally call UIBaseBean.java). Now, my UIBaseBean is @RequestScoped. As I understand, this shouldn't make a difference because my UserDetailBean is @ViewScoped, please correct me if I'm wrong.

The other detail that might make a difference is the setting of a variable in the constructor of both the UIBaseBean and the UserDetailBean. I want to display the location of the user in a toolbar at the top of my pages. To that end I created a variable in UIBaseBean:

protected String toolbarDescription;

I also provided the setter and getter in UIBaseBean. In UIBaseBean's constructor I define the variable:

toolbarDescription = "fix me";

That definition is just so I know to override the variable in the backing bean for any particular page in my application. In my UserDetailBean I assign a new value to the String toolbarDescription. This value is displayed on the detail.xhtml page. Otherwise, the bean for my detail.xhtml page is very straightfoward, it gets and sets properties for the display of data in the form on the detail.xhtml page.

The detail page is set up so the navigation to it happens with a redirect, and the navigation away (when the commandButton is pressed) happens with a redirect. I have tried using faces-config navigation rules with and without redirects, and implicit navigation with and without redirects, but the UserDetailBean constructor is always called twice.

Oh, I set a breakpoint on the toolbarDescription variable in my UserDetailBean constructor, which stops the program twice: when the page is first called, and again after I press the commandButton on the detail page.

From what I've described, can anyone tell me why my constructor is being called twice? Did I design my bean incorrectly, or is the problem deeper in my application?

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
import [package name].UIBaseBean;    
import java.util.Locale;
import javax.faces.bean.ManagedProperty;


@ManagedBean
@ViewScoped

public class UserDetailBean extends UIBaseBean {

@ManagedProperty(value = "#{param.action}")
private String action;

private String firstName;
private String lastName;
private String jobTitle;
private String DOH;
private String location;
private String status;
private String comments;
@ManagedProperty(value = "#{param.id}")
private String id;
private String tabTitle;

private boolean editMode;
private boolean viewMode;

private ClUserDetail dBUserDetail;      

    /** Creates a new instance of UserDetailBean */
    public UserDetailBean() {   
        toolbarDescription = CoreMsgBundle.getMessageFromResourceBundle("UserDetail", Locale.ENGLISH);
    }

回答1:

You need to remove the @RequestScoped and other related annotations from the UIBaseBean (and make it abstract).

Once that is done, you also need to fix the @ManagedProperty on #{param} to be either defined by <f:viewParam> or to be obtained by ExternalContext#getRequestParameterMap() instead. It's namely not possible to inject something which has a shorter scope into something which has a larger scope (because it's not clear which one should be injected since there can be more of them during the scope of the acceptor). JSF would throw an exception on that during bean's construction.