5

My problem is similar to this issue. I have a BaseBean which currently has just a single property which is annotated as a @ManagedProperty.

However, when I access the getter of this inherited managed property in the action method a commandbutton, it returns null. I debugged and confirmed that the base bean constructr was called twice - once on page load and next on click of the button as already described in the mentioned link.

I followed the suggestions as mentioned the article's chosen answer as well as this post, but to no avail.

Following is my code:

public abstract class BaseBean
{
   @ManagedProperty(value = "#{serviceLocator}")
   private IServiceLocator serviceLocator;

   public IServiceLocator getServiceLocator() {
      return serviceLocator;
   }

   public void setServiceLocator(IServiceLocator serviceLocator) {
      this.serviceLocator = serviceLocator;
   }
}

@ManagedBean
@ViewScoped
public class RegistrationBean extends BaseBean implements Serializable
{
   private static final long serialVersionUID = -6449858513581500971L;

   private String userID;
   private String password;
   private String firstName;
   private String lastName;
   private String email;
   private String addressLine1;
   private String addressLine2;
   private String city;
   private String state;
   private String pincode;

   private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationBean.class);

   /* getter / setters */

   public String register() 
   {
      String nextPage = null;
      try {
         RegistrationDetails userDetails = ModelBuilder.populateRegistrationData(this);
         int registrationID = getServiceLocator().getUserService().registerUser(userDetails);
         LOGGER.info("Registered user successfully. Registration ID - {}", registrationID);
         nextPage = "success";
      }
      catch (RegistrationException e) {
         LOGGER.error(e.getMessage());
      }
      return nextPage;
   }

   public void checkUserExists() 
   {
      int regID = getServiceLocator().getUserService().findUser(getUserID());

      if(regID > 0) {
         FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "User already exists !!", null);
         FacesContext.getCurrentInstance().addMessage(null, message);
      }
   }
}

Why would the constructor be called again on form submit ??? :/

The getter returns null even in the checkUserExists() method which is called via ajax on the blur event of the userID field.

EDIT : Added code for ServiceLocator..

@ManagedBean
@ApplicationScoped
public class ServiceLocator implements IServiceLocator
{
   private static final String USER_SERVICE = "userService";
   private static final String MOVIE_SERVICE = "movieService";

   @PostConstruct
   public void init() {
      final ServletContext sc = FacesUtils.getServletContext();
      this.webAppContext = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
      this.userService = (IUserService) webAppContext.getBean(USER_SERVICE);
      this.movieService = (IMovieService) webAppContext.getBean(MOVIE_SERVICE);
   }

   private ApplicationContext webAppContext;

   private IUserService userService;

   private IMovieService movieService;

   @Override
   public IUserService getUserService() {
      return userService;
   }

   @Override
   public IMovieService getMovieService() {
      return movieService;
   }
}
Community
  • 1
  • 1
Vrushank
  • 2,763
  • 3
  • 27
  • 41

2 Answers2

1

AFAIK you're trying to mix two answers: one for @RequestScoped mbeans and other for @ViewScoped mbeans. If you see the first link you've posted, BalusC is saying that you don't have to have @ManagedProperty in @ViewScoped mbeans as shown in ViewParam vs @ManagedProperty(value = “#{param.id})”.

If you can't pass the serviceLocator through a view param, you have to find another way to get that value (saving/retrieving it from session).

Also, check this info from BalusC explaining why the @ViewScoped mbean could be recreated on every request:

In a nutshell: the @ViewScoped breaks when any UIComponent is bound to the bean using binding attribute or when using JSTL or tags in the view. In both cases the bean will behave like a request scoped one. The first one is in my opinion a pretty major bug, the second one is only an extra excuse to get rid of the whole JSTL stuff in Facelets.

This is related to JSF 2.0 issue 1492. Here's an extract of relevance: This is a chicken/egg issue with partial state saving. The view is executed to populate the view before delta state is applied, so we see the behavior you've described. At this point, I don't see a clear way to resolve this use case. The workaround, if you must use view-scoped bindings would be setting javax.faces.PARTIAL_STATE_SAVING to false.

From


Based on your comment and edit, you can access to the @ApplicationScoped mbean by using the code provided here:

This would be the line:

FacesContext.getCurrentInstance().getExternalContext()
    .getApplicationMap().get("serviceLocator");

You have to use that code since, apparently, the @ViewScoped bean can't accept injection by @ManagedProperty.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • ServiceLocator is an application scoped bean which is just delegating calls to the services. I posted the ServiceLocator code in my question. Thanks, for pointing out my confusion.. :) – Vrushank Nov 04 '12 at 17:59
  • That seemed to work :D. I wasn't using this method since I assume it would be available via the injection. So, does this have to do something to Viewscope ??? – Vrushank Nov 04 '12 at 18:46
  • @VrushankDesai Apparently yes, it looks like you can't inject beans/values in `@ViewScoped` managed beans other way than using ``. It's very strange (even for me), but we have to use the technology the way it is atm =\. At least, you managed to solve your problem =). Don't forget to mark this post as an answer. – Luiggi Mendoza Nov 04 '12 at 19:40
0

The code for ServiceLocator isn't shown, so there's a number of open questions that may help identify an answer to your issue. I'll comment or ask a question, and perhaps something will trigger an "Aha!" for you:

  • Verify that ServiceLocator is in fact annotated with @ManagedBean.

  • Remember that you can't inject a bean with a shorter scope (life span) than the target bean. In this case, if ServiceLocator is, say, @RequestScoped, then it cannot be injected into your @ViewScoped bean.

  • are we to presume that IServiceLocator is an interface implemented by some managed bean ServiceLocator?

  • ServiceLocator smells like an EJB; if it is, use @EJB to inject an EJB.

Richard Sitze
  • 8,262
  • 3
  • 36
  • 48