问题
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;
}
}
回答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
- The benefits and pitfalls of @ViewScoped
Based on your comment and edit, you can access to the @ApplicationScoped mbean by using the code provided here:
- How to get application scope variable in jsf?
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.
回答2:
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
ServiceLocatoris 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
ServiceLocatoris, say,@RequestScoped, then it cannot be injected into your@ViewScopedbean.are we to presume that
IServiceLocatoris an interface implemented by some managed beanServiceLocator?ServiceLocatorsmells like an EJB; if it is, use@EJBto inject an EJB.
来源:https://stackoverflow.com/questions/13218329/managed-property-inheritance