2

I am seeing this strange behavior when using @ManagedProperty. I have 2 beans:

UserManager (SessionScoped)

@ManagedBean
@SessionScoped
public class UserManager extends BaseBean implements Serializable
{
   private static final long serialVersionUID = 1861000957282002416L;

   private User currentUser;

   public String login() 
   {
      // set value of currentUser after authentication
   }

   public User getCurrentUser() {
      return currentUser;
   }

   public boolean isLoggedIn() {
      return getCurrentUser() != null;
   }
}

CartBean (ALSO SessionScoped)

...
import javax.faces.bean.ManagedProperty;
...

@ManagedBean
@SessionScoped
public class CartBean extends BaseBean implements Serializable
{
   @ManagedProperty(value = "#{userManager.loggedIn}")
   private boolean loggedIn;

   public void updateCart(Movie selectedMovie)
   {
      if (!loggedIn) {
         return;
      }

      System.out.println("UPDATE CART REQUEST");

      int id = selectedMovie.getMovieID();

      if (cart.containsKey(id)) {
         cart.remove(id);
      }
      else {
         cart.put(id, selectedMovie);
      }
   }

   public void setLoggedIn(boolean loggedIn) {
      this.loggedIn = loggedIn;
   }
}

After logging in successfully, the value of loggedIn still remains false.

However, if I change the scope of CartBean to @ViewScoped, the value of loggedIn gets updated and I see the sysout.

As per my understanding and also after reading various articles, one can inject a managed bean or its property only if it is of the same or broader scope. But the "same scope" case does not seem to work in my code. What am I missing here?

I am using:

  • Mojarra 2.1.16
  • Spring 3.2
  • Hibernate 4.1
  • Tomcat 7.0.37
Vrushank
  • 2,763
  • 3
  • 27
  • 41

2 Answers2

5

@ManagedProperty annotation can only provide static injection, which means that the annotated property will get injected when and only when the holding @ManagedBean is instantiated.

When you deploy your application, I believe your CartBean was referenced right at the beginning through things like the View cart button, etc. As a consequence, the injection took place too early and since the bean is @SessionScoped, you will carry the initial false value till the end of time :).

Instead of injecting only the boolean field, you should, instead, inject the whole UserManager bean:

@ManagedBean
@SessionScoped
public class CartBean extends BaseBean implements Serializable {
   @ManagedProperty(value = "#{userManager}")
   private UserManager userManager;

   public void updateCart(Movie selectedMovie) {
       if (!userManager.isLoggedIn()) {
           return;
       }

       ...
   }
}
Mr.J4mes
  • 9,168
  • 9
  • 48
  • 90
  • Interesting. You've confirmed this yourself? Or some reference sources? – kolossus Apr 01 '13 at 20:01
  • From [ManagedProperty](http://docs.oracle.com/javaee/6/api/javax/faces/bean/ManagedProperty.html), it does vaguely mention that `The value of the value() attribute may be a literal String or a ValueExpression. If the latter, the expression must not be evaluated until the bean is instantiated.` – Mr.J4mes Apr 01 '13 at 20:47
  • You're right, it is vague, but it's there. You have my vote :) – kolossus Apr 01 '13 at 21:29
  • It is quite an interesting insight. You've got my vote as well. Hope that some day we'll get bilateral bindings in JSF. – skuntsel Apr 02 '13 at 05:24
  • Agreed with kolossus and skuntsel. This weird behavior pretty much constraints the use of managed property injection between beans of same scope as the scope gets broader... – Vrushank Apr 02 '13 at 05:29
  • 1
    @Vrushank, I can see why it's this way. It's going to be an expensive operation to keep such fine-grained level of injection up to date. Better managed when you have access to an entire object than member variables – kolossus Apr 02 '13 at 06:52
0

The solution is using Omnifaces it worked for me each time the value change you will get the new value

@ManagedBean
@ViewScoped
public class CartBean extends BaseBean implements Serializable {

   private boolean loggedIn;

   public void updateCart(Movie selectedMovie) {
loggedIn=Faces.evaluateExpressionGet("#{userManager.loggedIN}");
       if (!userManager.isLoggedIn()) {
           return;
       }

       ...
   }
}
maresca
  • 11
  • Without omnifaces one can use: `FacesContext.getApplication().evaluateExpressionGet(context, "#{userManager.loggedIN}", Boolean.class);` – djmj Dec 21 '16 at 03:18