Simple question from a beginner at JSF:
I have very simple JSF form:
<h:form>
<p>#{messages.loginTextfieldUsername}</p>
<h:inputText value="#{userServiceImpl.user.name}" />
<p>#{messages.loginTextfieldPassword}</p>
<h:inputSecret value="#{userServiceImpl.user.password}" />
<h:commandButton value="#{messages.loginButtonLogin}" action="#{userServiceImpl.authenticateUser}" />
</h:form>
The userServiceImpl class is:
#Named
#RequestScoped
public class UserServiceImpl implements UserService {
private UserSession userSession;
private User user;
#Inject
public UserServiceImpl(UserSession userSession) {
this.userSession = userSession;
}
#PostConstruct
public void prepareService() {
user = new User();
}
#Override
public View authenticateUser() {
userSession.setLoggedUser(user);
return View.MAIN;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
My goal is pretty simple: when the user hits the login button, I want to authenticate the user.
The problem is:
When the authenticate method is called, the User attributes are null. I debugged the application and the getUser method is called and the values are properly set, but at some point (which I did not find [yet]) before the authenticateUser is called the User attributes are set to null...
I'm aware that this is a pretty basic question... but are you able to point out where my mistake is?
Thanks.
Based on your previous question, you seem to have experimented with <managed-bean-scope> of none in faces-config.xml for some reason. The problem symptoms matches exactly when using #ManagedBean #NoneScoped. You seem to have configured this bean in faces-config.xml as well on a none scope which totally explains this problem. With the none scope, a brand new bean instance is been created everytime when #{userServiceImpl} is been evaluated in EL. Your form submit has thus effectively created 3 beans: one where the user name is set, another one where user password is set and another one where action is invoked.
You need to remove the managed bean configuration from faces-config.xml. You should not use it when you intend to use #Inject (or #ManagedBean). The faces-config.xml way of configuring beans is a leftover from old JSF 1.x ages when annotations weren't available. As of JSF 2.x it would only override any bean management annotations.
Related
Let's assume a simple Jsf example with a xhtml page, a ManagedBean, a service and an JPA entityClass. I have a lot of usecases with the following structure:
Hold an entity in my bean
Do actions on the entity
Do rendering on the updated entity
Some easy example, so everyone will understand
Entity:
public class Entity {
private long id;
private boolean value;
...
// Getter and Setter
}
Dao:
public class EntityService {
// Entity Manger em and other stuff
public void enableEntity(long id) {
Entity e = em.find(id);
e.value = true;
em.persist(e);
}
}
Managed Bean:
#ManagedBean
#RequestScoped/ViewScoped
public class EntityBean() {
#EJB
private EntityService entityService;
private Entity entity;
#PostConstruct
public void init() {
// here i fetch the data, to provide it for the getters and setters
entity = entityService.fetchEntity();
}
public void enableEntity() {
entityService.enableEntity(entity.getId);
}
// Getter and Setter
}
and finally a simple xhtml:
<html>
// bla bla bla
<h:panelGroup id="parent">
<h:panelGroup id="disabled" rendered="#{not EntityBean.entity.value}>
<p:commandButton value="action" action="#{EntityBean.enableEntity}" update="parent" />
</h:panelGroup>
<h:panelGroup id="enabled" rendered="#{EntityBean.entity.value}>
// other stuff that should become visible
</h:panelGroup>
</h:panelGroup>
</html>
What i want to achieve:
Always show the up to date entity in every request!
What i already tried
I tried with a dao-fetch in my getter. But you can read everywhere that this is bad practice, because jsf will call the getter more than once (but for now the only way i can keep them really up to date).
I tried RequestScoped Beans. But the Bean will be created before the action is done, and is not recreated on the update call and the value will be outdated (Makes sense, since this is one request, and the request starts with the click on the button).
I tried ViewScoped Beans and added an empty String return value to my method. My hope was, that this redirection will recreate the Bean after the action was processed. But this was not the case.
I tried to call the refetch function manually after every method i used. But I have some cross bean actions on the same entity (My real entities are way more complex than this example). So the different Beans do not always know, if and when the entity has changed.
My Questions:
Can this be done with any kind of Scope? Let's say that every request will fetch the data from my PostConstruct again.
There must be a better solution than the dao-fetch in the getter method
This seems to be a fundamental problem for me, because getting the up to date data is essential for my app (data is changed often).
Using Primefaces 6.1 and Wildfly 10.x
What do you think about this?
A request scoped bean which will be created for update, too and does only one fetchEntity() per request.
<f:metadata>
<f:viewAction action="#{entityBean.load()}" onPostback="true"/>
</f:metadata>
#ManagedBean
#RequestScoped
public class EntityBean() {
#EJB
private EntityService entityService;
private Entity entity = null;
public void load() {}
public Entity getEntity() {
if(entity == null) {
entity = entityService.fetchEntity();
}
return entity;
}
public void enableEntity() {
entityService.enableEntity(getEntity().getId);
}
// Getter and Setter
}
Edit: The comment section solved my problem! The problem was that I was using incorrect imports for the Scopes.
I have a simple JSF application (login, pull data from database, allow user to edit data). It works well, I want to update the code to use CDI (Weld), but I am having trouble.
I am following / looking at: http://docs.jboss.org/weld/reference/latest/en-US/html/example.html
Original stuff without Weld:
login.xhtml
<h:form id="inputForm">
<h:panelGrid columns="2" cellpadding="5" cellspacing="1">
<h:outputText id="nameDesc" value="Name"></h:outputText>
<h:inputText id="nameInput" value="#{login.loginName}" binding="#{name}"></h:inputText>
<h:outputText id="passwordDesc" value="Password"></h:outputText>
<h:inputSecret id="passwordInput" value="#{login.password}" binding="#{password}"></h:inputSecret>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login(name.value, password.value)}"/>
</h:form>
LoginBean.java:
#ManagedBean(name="login")
#SessionScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty(value="#{db}")
private DatabaseBean db;
private String password;
private String loginName;
// other stuff and functions
public String getLoginName () {
return loginName;
}
public void setLoginName (String name) {
this.loginName = name;
}
public String getPassword () {
return password;
}
public void setPassword (final String password) {
this.password = password;
}
public void setDb(DatabaseBean db) {
this.db = db;
}
DatabaseBean.java:
#ManagedBean(name="db", eager=true)
#ApplicationScoped
public class DatabaseBean implements Serializable {
#PostConstruct
public void init() {
//... connect to database etc
}
}
---------What I tried to get it running with Weld (only changes from above to make it a bit shorter): --------
LoginBean.java, changed to #Named from #ManagedBean, added #Inject for DatabaseBean
#Named("login")
#SessionScoped
public class LoginBean implements Serializable {
// stuff
private #Inject DatabaseBean db;
}
DatabaseBean.java, changed to #Named from #ManagedBean:
#Named("db")
#ApplicationScoped
public class DatabaseBean implements Serializable {
}
LoginBean has a function:
public String login(String name, String password) {
System.out.println("login called"+name);
// other stuff
}
With my second implementation (the one where I try to use Weld), the print is called once: "login called", and the username is empty (I checked this with name.IsEmpty()).
I have also tried injecting it by constructor:
loginBean.java
#Inject
public LoginBean(DatabaseBean db) {
System.out.println("constructor");
this.db = db;
}
When I do this the I get lots of "constructor" prints, so it is called several times, but I don't see why - I guess this is the problem though, only one instance of LoginBean gets the input (username and password) and then lots of new ones are created for some reason. Why is that?
I use Eclipse and Tomcat8 to run it.
Thank you for reading!
managed bean constructor called multiple times
CDI may call constructor more often than expected while generating/creating enhanced subclasses/proxies. See also Field.get(obj) returns all nulls on injected CDI managed beans, while manually invoking getters return correct values. Just do not log constructor invocation, it would only confuse yourself. #PostConstruct is the only interesting method to hook on.
the print is called once: "login called", and the username is empty (I checked this with name.IsEmpty()).
As to the concrete problem of form input values being null when the action method is invoked, and thus the #SessionScoped CDI managed bean seemingly being recreated on every access, this matches the behavior of a #Dependent scoped bean. This is the default scope when no valid CDI managed bean scope can be found. See also What is the default Managed Bean Scope in a JSF 2 application?
This in turn suggests you imported #SessionScoped from the wrong package. Make sure it's from the javax.enterprise.context package and not from e.g. javax.faces.bean. JSF managed bean scopes are not recognizable as valid CDI managed bean scopes.
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
#Named("login")
#SessionScoped
public class LoginBean implements Serializable {
// ...
}
This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between
I'm looking for some piece of code for setting a property in a JSF managed bean. My first idea was something like that:
<c:set var="#{loginBean.device}" value="mobil"></c:set>
That means I want to set the attribute device to the value "mobil" without a button have to been clicked.
Yes, you can use c:set for this purpose.
<c:set value="mobil" target="#{loginBean}" property="device" />
Doc: http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/c/set.html
However, setting a static value rarely makes sense. You might consider to set a default value directly in your managed bean class. Also in terms of maintainability since you can handle constants better in the Java code than in the view layer.
I think you want the JSF tag child tag setPropertyActionListener. You can set this as a child tag in any ActionComponent.
<h:anyActionComponent id="component1">
<f:setPropertyActionListener target="#{loginBean.device}" value="mobil" />
</h:anyActionComponent>
UPDATE:
I originally misunderstood the users problem. They have a page, and they want a property to be set when the page loads. There is a couple ways to do this, but both are a little different. If you want to set a property to a value after every postback then you can use the #PostConstruct annotation on a ManagedBean method.
#PostConstruct
public void initializeStuff() {
this.device = "mobil";
}
Now if I have a ViewScoped or SessionScope bean that needs to be initialized with a default value just once when the page loads then you can set a phase lifecycle event that will run after every postback and check to see if the page should be initialized or not.
mah.xhmtl:
<f:event listener="#{loginBean.initialize()}" type="preRenderView" />
LoginBean:
public void initialize() {
if (this.device == null)
this.device = "mobil";
}
I am not able to Comment: If you need the value to be ready on page on load, you could use Managed Bean to directly initialize value or use its constructor or #PostConstruct to do the same.
#ManagedBean
#ResquestScoped
public class LoginBean {
private String device = "some value";
//Using Constructor
public LoginBean() {
device = getvalueFromSomewhere();
}
//Using PostConstruct
#PostConstruct
public void init() {
device = getvalueFromSomewhere();
}
}
Instead of setting the value in the xhtml file you can set via another ManagedBean. For instance if you have managedBean1 which manages page1.xhtml and managedBean2 which manages page2.xhtml. If page1.xhtml includes page2.xhtml like:
<ui:include src="page2.xhtml"/>
in managedBean1 you can have at the top
#ManagedProperty(value = "#{managedBean2}")
private ManagedBean2 managedBean2;
and in the PostConstruct
#PostConstruct
public void construct() {
managedBean2.setProperty(...);
}
worked for me anyway...
Using JSF 2.0 and Spring, I use an #RequestScope managed bean. This bean stores information about the logged-in user. It loads the user from the DB in a #PostConstruct method:
#PostConstruct
public void init() {
String username = login.getUsername();
user = userDao.load(username);
}
The logged-in user can then trigger on action on the page that updates the user in database (using another managed bean).
However, the #RequestScope bean is constructed at the beginning of the request, which is before the call to the updating action. As a result, when the page is redisplayed, the User variable still has its old values.
My question is: do I have a way to run my loading method not at the beginning of the request, but after the request has been sent? Or am I dealing with this in the wrong way?
Thanks for your insight,
Sébastien
The logged-in user can then trigger on action on the page that updates the user in database (using another managed bean).
The same managed bean should have been updated at that point. If you can't reuse the same managed bean for some reason, then you should manually do it by accessing it in the action method and calling the setters yourself.
Update: based on the comments, here's how the beans should be declared and injected and used in your particular requirement:
#ManagedBean(name="#{login}")
#SessionScoped
public class LoginManager {
private String username;
// ...
}
#ManagedBean(name="#{user}")
#RequestScoped
public class UserManager {
#ManagedProperty(value="#{login}")
private LoginManager login;
private User current;
#PostConstruct
public void init() {
current = userDAO.find(login.getUsername());
}
// ...
}
#ManagedBean(name="#{profile}")
#RequestScoped
public class ProfileManager {
#ManagedProperty(value="#{user}")
private UserManager user;
public void save() {
userDAO.save(user.getCurrent());
}
// ...
}
<h:form>
<h:inputText value="#{user.current.firstname}" />
<h:inputText value="#{user.current.lastname}" />
<h:inputText value="#{user.current.birthdate}" />
...
<h:commandButton value="Save" action="#{profile.save}" />
</h:form>