Search code examples
jsfmanaged-beanmyfaces

ManagedProperty is not available


I have two ManagedBeans (SessionHandler and OrderHandler). Both are session scoped.

SessionHandler:

@ManagedBean(name="session")
@SessionScoped
public class SessionHandler {

    private Account account;

    public String login() {
        try {
            // ... login method ...

            return("bookinglist.xhtml?faces-redirect=true");
        }
        catch (Exception e) {
            // ... exception handling ...
        }
    }

    // ... getter & setter ...
}

OrderHandler:

@ManagedBean(name="order")
@SessionScoped
public class OrderHandler {

    @ManagedProperty(value="#{session.account}")
    Account account; // getter and setter

    public OrderHandler() {
        this.createList();
    }

    private void createList() {
        // method creates an ArrayList of bookings
        // it uses this.account.getId() for a SQL statement
    }
}

In bookinglist.xhtml I want to display a welcome text and my list:

<p>Welcome, #{sessions.account.name}!</p>

<ui:repeat value="#{order.bookingList}" var="item">
    <!-- ... items ... --->
</ui:repeat>

The welcome text is displayed, but my list is empty because in my sql statement the accountID is null. A statement with accountID = 1 (as example) works. Later in the booking process I can use the accountID (without doing anything to redeclare or overwrite it).

I guess the problem is, that the property isn't available immediately after the login... But I don't know why. Can someone help me?


Solution

  • When using @ManagedProperty, one important fact to keep in mind of is that such property will be injected once after bean constructor is called. The reason is because JSF can only inject a property when the bean is fully constructed.

    In effect, it means that, from your current code, account will be injected after createList() is called. If you debug OrderHandler, you will very likely see the following execution sequence:

    // bean instantiation step
    -> OrderHandler constructor called
       -> createList called
    
    // bean property injection step
    -> Account injected
    

    To solve this, you need to call createList() after constructor is finished, and account is already injected. You can achieve that with a method with @PostConstruct annotation:

    @PostConstruct
    private void init() {
        // this will be called after constructor call, and property injection
        this.createList();
    }
    

    You can read more about @PostConstruct annotation here:

    http://docs.oracle.com/javaee/7/api/javax/annotation/PostConstruct.html