Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ManagedProperty(value = "#{param.id}") in a non-request Scope Bean

I need to pass a parameter (POST) to a @managedBean, I used managed properties like this:

@ManagedProperty(value = "#{param.id}")
private int id;

And the scope of the Bean is ViewScope

I end up with this error:

Unable to create managed bean receipt. The following problems were found: - The scope of the object referenced by expression #{param.id}, request, is shorter than the referring managed beans scope of view

What can I do?

arjan take a look:

My page: Facelet Title

<form method="post" action="faces/index.xhtml">
  <input name="id" value="4" />
  <input type="submit" value="submit" />
</form>

<h:form>
  <h:commandLink value="click" action="index">
    <f:param id="id" name="id" value="20"/>
  </h:commandLink>
</h:form>

like image 693
ehsun7b Avatar asked Jan 02 '11 18:01

ehsun7b


People also ask

What is @ManagedProperty?

@ManagedProperty Annotation JSF is a simple static Dependency Injection (DI) framework. Using @ManagedProperty annotation, a managed bean's property can be injected in another managed bean.

What is managed property in JSF?

JSF @ManagedProperty annotation is used to inject the dependencies instead of object having to acquire those dependencies on its own. Property from injected object can be accessed through simple access approach in facelets. Property from injected object can be accessed through deep access approach in facelets.


2 Answers

Two ways:

  1. Make the bean request scoped and inject the view scoped one as another @ManagedProperty.

    @ManagedBean
    @RequestScoped
    public class RequestBean {
    
        @ManagedProperty(value="#{param.id}")
        private Integer id;
    
        @ManagedProperty(value="#{viewBean}")
        private ViewBean viewBean;
    }
    

    The view scoped bean is available during @PostConstruct and action methods of request scoped bean. You only need to keep in mind that the id can get lost when you do a postback to the same view without the parameter.

  2. Or, grab it manually from the request parameter map during bean's initialization.

    @ManagedBean
    @ViewScoped
    public class ViewBean {
    
        private Integer id;
    
        @PostConstruct
        public void init() {
            id = Integer.valueOf(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"));       
        }
    }
    

    This way the initial id is available during the entire view scope.

like image 135
BalusC Avatar answered Sep 23 '22 08:09

BalusC


As an alternative to grabbing the parameters directly from the request in your bean, you can use view parameters.

These need to be declared on the Facelet where you use your managed bean as follows:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
>
    <h:body>

    <f:metadata>
        <f:viewParam id="id" name="id" value="#{myBean.id}" />        
    </f:metadata>

    <!-- Rest of Facelet here -->   

    </h:body>
</html>

If you now request this page, the setter of the backing bean will be called with the request value provided for the id parameter. This works for both GET and (non-faces) POST requests.

The advantage is that you can use the standard JSF converters and validators here. Of course if your managed bean is not tied to a particular view then this solution is less ideal.

A small peculiar thing to watch out for is that when doing a normal faces postback after the initial request that provided the view parameter, the setter in your bean will be called again, even if the bean is in view scope and no new value is explicitly provided.

To test that this works, I've used the following managed bean:

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

@ManagedBean
@ViewScoped
public class MyBean {

    Long id;

    @PostConstruct
    public void test() {
        System.out.println("post construct called");
    }

    public void actionMethod(ActionEvent event) {       
        System.out.println("action called");        
    }

    public Long getId() {
        return id;
    }

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

}

And the following Facelet:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
>
    <h:body>

        <f:metadata>
            <f:viewParam id="id" name="id" value="#{myBean.id}" />        
        </f:metadata>

        <h:outputText value="#{myBean.id}"/>

        <h:form>
            <h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
        </h:form>

        <form method="post">
            <input name="id" value="4" />
            <input type="submit" value="submit" />
        </form>

    </h:body>
</html>

Enter a number in the input field and click the submit button. If the number is printed back on the screen the test has succeeded. Note that the second form is a regular form and does not post any JSF state along. I tested this on JBoss AS 6 and it works. Proving the id parameter as a GET parameter also works.

like image 22
Arjan Tijms Avatar answered Sep 24 '22 08:09

Arjan Tijms