IllegalStateException when trying to .getSessionMap() from a Session Scoped Bean
Asked Answered
J

1

1

I'm new to Java and JSF. I need help with an IllegalStateException. Here's the scenario:

In my current project i have this Session Scoped bean for the application menu:

public final class MenuBean implements Serializable{  
    private MenuModel model;
    private FacesContext context = FacesContext.getCurrentInstance();

    public MenuModel getModel() {
        return model;
    }

    public MenuBean() {
        updateMenu();
    }

    public void updateMenu(){
        Map session = (Map<String,Object>) context.getExternalContext().getSessionMap();
        EUser user = (EUser) session.get(UserBean.USER_SESSION_KEY);

        ...
    }

    private MethodExpression createMethodExpression(String action) {  
        ...  
    }
}

At some point of my logic, i need to update the menu, so i do this:

ExternalContext extContext = context.getExternalContext();
Map sMap = (Map<String,Object>) extContext.getSessionMap();

MenuBean menu = (MenuBean) sMap.get("menuBean");
menu.updateMenu();

The bean constructs fine, but when i try to manually update it as shown above, i get and IllegalStateException on the 1st line of the update method updateMenu()

I don't understand what's wrong, since I can get the session map with that same call whe the menu is build in the first time.

Also, using the NetBeans debugger, i can see that the instance of MenuBean is correctly recovered.

Can you guys help me?

Joyner answered 8/5, 2012 at 19:51 Comment(0)
E
2

The FacesContext is stored in the HTTP request thread. You should absolutely not declare and assign it as an instance variable of an instance which lives longer than the HTTP request (and preferably also just not when it's already request based -it's bad design). The FacesContext instance is released and invalidated when the HTTP request finishes. In any subsequent HTTP request the instance is not valid anymore. There's means of an illegal state. That explains the IllegalStateException you're seeing.

You need to remove the following line:

private FacesContext context = FacesContext.getCurrentInstance();

And fix your code to get it only threadlocal in the method block:

Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
// ...

You can always assign it as a variable, but that should only be kept threadlocal:

FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
// ...

Unrelated to the concrete problem, using @ManagedProperty has been easier in this particular case.

public final class MenuBean implements Serializable {  

    @ManagedProperty("#{user}")
    private EUser user;

    // ...
}

JSF will then inject it for you.

Esau answered 8/5, 2012 at 21:38 Comment(6)
Hi BalusC. Thanks so much. That solved it. I saw that (bad) design in a tutorial, but then i changed the scope of my bean and did not notice that this could happen.Joyner
I did not quite understand how the @ManagedProperty would work. How will the container resolve "#{user}" ? do i have to define this?Joyner
It just evaluates the EL expression and calls the getter method with the retrieved object directly after construction of MenuBean. Here I assume that your UserBean.USER_SESSION_KEY has a value of user, so that it's effectively available in EL scope as #{user}.Esau
I see. But as far as I understood things in JSF, shouldn't this EL expression be like "#{userBean.user}" ?Joyner
I have no idea as this detail is not present in your code as you're working with constants. But it should be just the same attribute name as you've in UserBean.USER_SESSION_KEY and the same EL expression as you would use in the XHTML file to get the user from the session scope.Esau
Ok, i got it. Thanks again BalusC. You rock!Joyner

© 2022 - 2024 — McMap. All rights reserved.