@ManagedProperty on #{param} does not work in @ViewScoped

ChuongPham picture ChuongPham · Apr 16, 2011 · Viewed 10.5k times · Source

My bean has this:

@ManagedBean
@ViewScoped
public class BookBean implements Serializable
{       
    @ManagedProperty(value = "#{param.id}") // does not work with @ViewScoped
    private String id;

    public void init()
    {
        id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id")
        if (id != null) {
            System.out.println("ID: " + id);
            currentBook = bookService.find(id);
        }
    }

    @PostConstruct
    public void post()
    {   
        // does not work with @ViewScoped
        System.out.println("ID: " + id);
        currentBook = bookService.find(id);    
    }

    public String getId() {
        return id;
    } 

    public void setId(String id) {
       this.id = id;
    }
}

And the destination Facelet has this:

<f:metadata>
    <f:viewParam name="id" value="#{bookBean.id}">
        <f:event type="preRenderView" listener="#{bookBean.init}" />
    </f:viewParam>
</f:metadata> 

Through testing, I've noticed that @ManagedProperty and @PostConstruct only work with @RequestScoped bean.

For @ViewScoped bean, I found that I had to do this FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id") to get the value of the id parameter.

Is this the only way to get a request parameter's value with @ViewScoped?

Any thoughts?

Answer

BalusC picture BalusC · Apr 16, 2011

The view scope is broader than the request scope. The @ManagedProperty can only set properties which have the same or broader scope as compared to the managed bean's scope.

Just keep using <f:viewParam> with <f:event>. You should only not nest them in each other.

<f:metadata>
    <f:viewParam name="id" value="#{bookBean.id}" />
    <f:event type="preRenderView" listener="#{bookBean.init}" />
</f:metadata> 

with

@ManagedBean
@ViewScoped
public class BookBean implements Serializable {

    private String id;

    public void init() {
        if (id != null) {
            currentBook = bookService.find(id);
        }
    }

    // ...
}

The <f:viewParam> will set the request parameter and the <f:event> will execute the listener method after setting of those parameters.

The @PostConstruct works fine on view scoped beans as well, but it only runs directly after bean's construction and all dependency injections are been set (such as @ManagedProperty, @EJB, @Inject, @Resource, etc). The <f:viewParam> however sets the property thereafter, so it's not available in @PostConstruct.