JSF managed-bean EJB injection
I have an EJB (PersonManager) in the Enterprise Application modul, which injects another EJB (Person):
@Stateful
public class PersonManager implements PersonManagerLocal {
@EJB
private PersonLocal person;
@Override
public void setPersonName(String name) {
person.setName(name);
}
@Override
public String getPersonName() {
return person.getName();
}
}
I want to use the PersonManager EJB in a JSF web app. I define it in the faces-config.xml:
<managed-bean>
<managed-bean-name>personManager</managed-bean-name>
<managed-bean-class>ejb.PersonManager</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
The problem is that, the injection of the PersonLocal EJB doesn't happen. The person property is always NULL. What did I wrong?
But if I inject the PersonManager in a JSF managed bean like this:
@ManagedBean
@RequestScoped
public class Index {
@EJB
private PersonManagerLocal personManager;
....
IT WORKS. I need the first scenario, please help me :-D
You are mixing the responsibilities of EJBs and JSF managed beans. The faces-config.xml
registers only JSF artifacts, such as managed beans and not EJBs. Your registration in faces-config.xml
<managed-bean>
<managed-bean-name>personManager</managed-bean-name>
<managed-bean-class>ejb.PersonManager</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
does basically exactly the same as
@ManagedBean
@SessionScoped
public class PersonManager {
// ...
}
In other words, you're registering the class as a JSF managed bean which is available in views by #{personManager}
. This does not represent the same instance as is managed by the EJB container. You can and should not use faces-config.xml
to register EJBs. There you use the annotations from the javax.ejb
package for, such as @Stateless
and @Stateful
. That's all you need to register an EJB.
Actually, registering JSF managed beans in faces-config.xml
is an old JSF 1.x way which has in JSF 2.x been replaced by the new @ManagedBean
annotation.
Update the proper approach would be:
View (the Facelets file):
<h:form>
<h:inputText value="#{personManager.person.name}" />
...
<h:commandButton value="Save" action="#{personManager.save}" />
<h:messages />
</h:form>
Controller (the JSF managed bean):
@ManagedBean
@ViewScoped
public class PersonManager implements Serializable {
private Person person;
@EJB
private PersonService personService;
@PostConstruct
public void init() {
person = new Person();
}
public void save() {
personService.create(person);
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Person successfully created, new ID is " + person.getId()));
}
// ...
}
Model (the JPA entity):
@Entity
public class Person implements Serializable {
@Id
private Long id;
private String name;
// ...
}
Service (the stateless EJB):
@Stateless
public class PersonService {
@PersistenceContext
private EntityManager em;
public void create(Person person) {
em.persist(person);
}
// ...
}