I have and CDI bean UserController annotated as #ConversationScope with an attribute named as user with getters and setters exposed.
#ConversationScoped
#Named("userController")
public class UserController implements Serializable {
private User user;
#PostConstruct
public void init() {
this.user = new User();
}
//getters and setters ommited...
}
I also have an second class with my Observers.
#ConversationScoped
public class UserObservers implements Serializable {
#Inject private UserController controller;
public void createObserver(#Observes #MyQualifier MyEvent event) {
this.controller.getUser().setName("Test Name");
}
}
The user property is filled in my interface and i want my observer to change the name of the user, but the user property always returns null.
Its like my observer is located in a different conversation.
Can i have more than one conversation active for the same user session?
Update:
When i change my navigation rule to redirect, the code works correctly.
Can it be that you did not start the conversation? Then you will get a new conversation for each request. Injecting the conversation into both beans and debugging its state / id should certainly reveal the problem.
Related
So I have a bean which contains a category field. If that category field is set to a specific value, for instance "MATCH" I want to initialize a bean. However doing it in the setter of the category is kind of an anti pattern and I'd like to know if in this case that could be considered alright or maybe there is a better way to do it.
I don't want to use postConstruct because the bean is used a really low percentage of the time. So having DB calls in PostConstruct is non sens in my opinion in this case.
#Named
#ViewScoped
public class BeanA implements Serializable {
private Category category;
#Inject
private MatchCreation matchCreation;
public void setCategory(Category category) {
this.category = category;
if("MATCH".equals(category.getName()){
matchCreation.init(); // I'll put a check here to not initialize it twice
}
}
}
#Named
#ViewScoped
public class MatchCreation {
private List<Team> teamList;
private List<Map> mapList;
#EJB
private TeamService ts;
#EJB
private MapService ms;
public void init() {
teamList = ts.getProTeams();
setMapList(ms.getAllMaps());
}
}
Also in that particular bean I have 9 injections. I don't have to be afraid to use those right, I don't have to try to have the bare minimum ?
I'm trying to inject a bean in a stateless EJB. But i would like that bean be different when EJB is called from a ManagedBean or from a EJB Timer.
Here is my EJB in which i inject a User bean:
MyEjb.java
#Stateless
class MyEjb{
#Inject
#CurrentContext
private User user;
public void foo(){
System.out.println(user);
}
}
Here is a EJB Timer that use the EJB:
TimerTest.java
#Singleton
#Startup
class TimerTest {
#EJB
private MyEjb myEjb;
#Timeout
public void doIt(Timer timer) {
myEjb.foo();
}
#Produces
#CurrentContext
public User produceCurrentUserInEjbTimer(){
return new User("system");
}
}
Finally, the ManagedBean using MyEjb :
MyManagedBean.java
#ManagedBean
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo();
}
#Produces
#CurrentContext
#RequestScoped
public User produceCurrentUserInManagedBean(){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
}
When the timeout is reach, i would like that foo method of MyEbj use the system User created by the method produceCurrentUserInEjbTimer.
And when the bar method of the ManagedBean is invoked, i would like that foo method of MyEbj use the remote User of the FaceContext (created by the method produceCurrentUserInManagedBean).
I would rather have only one producer that checks if FacesContext.getCurrentInstance() != null then call the apropriate code:
public User produceCurrentUser(){
if(FacesContext.getCurrentInstance() != null){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
else{
return new User("system");
}
}
You can also inject you User directly on the timer or the ManagedBean and then use InjectionPoint object to know to which class your User is injected:
public User produceCurrentUser(InjectionPoint injectionPoint){
System.out.println(injectionPoint.getBean());
}
You should also use #Named and #javax.enterprise.context.SessionScoped as you have CDI on your application instead of #ManagedBean.
UPDATE
I'm not sure that there is a direct method to get the context of the injection, it wil be possible throw CDI extension but I've never try it.
What about obtaining a contextual instance by programmatic lookup:
#Stateless
class MyEjb{
#Inject #Any Instance<User> userSource;
public void foo(String context) // you should define contexts your self as jms, jsf ...
{
// Every expected context will have a qualifier
Annotation qualifier = context.equals("jsf") ?
new JSFQualifier() : new JMSQualifier();
User p = userSource.select(qualifier).get();
System.out.println(user);
}
}
This was you can inject your EJB and pass the context param to foo:
#Named
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo("jsf");
}
}
I have a little javaee webproject and i need bean injection in it. i have a tomee server with cdi enabled. Here is a little test case.
Here is my #SessionScoped User object
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
#SessionScoped
public class User implements Serializable {
String userName;
public User () {}
public User (String userName) { this.userName = userName; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
}
and here are my two nearly identical beans:
#Named
#RequestScoped
public class BeanOne {
private String message;
#Inject User user;
#PostConstruct
public void init() { user = new User("TestName"); }
public String getMessage() { return user.getUserName(); }
}
In this bean i create a new user. the method getMessage returns the correct user name. I thought the user should still exist in the second bean because its #SessionScoped. Here is my second bean.
#Named
#RequestScoped
public class BeanTwo {
private String message;
#Inject User user;
public String getMessage() { return user.getUserName(); }
}
But in this bean the user.getUserName() returns null. How am i supposed to inject a #SessionScoped bean?
This happens because you have manually initialized user object in BeanOne init method. The purpose of dependency injection is to let some container create instances of objects for you, so you should never initialize objects manually. So just set a name for this user and it will be visible during session for all other beans.
#PostConstruct
public void init() { user.setUserName("TestName"); }
I have changed my JSF manged bean to a CDI named bean. However I get a strange behavior that when I update a record using JPA merge() through EJB, a new record is being created instead of updating the entity.
my previous implementation
#ManagedBean
#ViewScoped
public class bean implements serializable{
#EJB Service service;
private Entity entity;
#PostConstruct
private void init(){
int id = 1;
this.entity = (Entity) service.findEntity(Entity.class, 1);
}
//invoke after editing entity
public void update(){
service.update(entity);
}
}
#Stateless
public class Service implements Serializable{
#PersistenceContext(unitName="unitName")
private EntityManager em;
public void update(Object obj){
em.merge(obj);
}
public Object find(Class klass, object pk){
return em.find(klass, pk);
}
}
Result: entity is being updated
My new implementation
#Named
#ConversationScoped
public class bean implements Serializable{
//unchanged
}
Result: entity is not being updated, and instead a new record is being created with all fields being duplicated except the id (pk) as it is an auto generated integer, and a new id is generated for the new record; Why is this happening?
Did you really want to chane the scope of your bean to ConversationScoped. I would have thought that you would use
"javax.faces.view.ViewScoped"
[not javax.faces.bean.ViewScoped!!] and just use #Named. Changing a bean scope changed the whole semantics.
I have a managed bean (SessionScope as follow)
#ManagedBean(name="login")
#SessionScoped
public class Login implements Serializable {
private String userSession;
public Login(){
}
}
In this managedbean, somewhere in the login function, i store the email as a session.
I have another managed bean called ChangePassword (ViewScoped). I need to access the value of the email which is stored in the userSession.
The reason of doing so is that i need to find out the current userSession(email) before i can complete the change password function. (Need change password for that specific email)
How do i do so? New to JSF, appreciate any help!
Just inject the one bean as a managed property of the other bean.
#ManagedBean
#ViewScoped
public class ChangePassword {
#ManagedProperty("#{login}")
private Login login; // +setter (no getter!)
public void submit() {
// ... (the login bean is available here)
}
// ...
}
See also:
Communication in JSF 2.0 - Injecting managed beans in each other
In JSF2, I usually use a method like this:
public static Object getSessionObject(String objName) {
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext extCtx = ctx.getExternalContext();
Map<String, Object> sessionMap = extCtx.getSessionMap();
return sessionMap.get(objName);
}
The input parameter is the name of your bean.
if your session scoped bean is like this :
#ManagedBean(name="login")
#SessionScoped
public class Login implements Serializable {
private String userSession;
public Login(){
}
}
you can access the values of this bean like :
#ManagedBean(name="changePassword")
#ViewScoped
public class ChangePassword implements Serializable {
#ManagedProperty(value="#{login.userSession}")
private String userSession;
public ChangePassword (){
}
}
public static Object getSessionObj(String id) {
return FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(id);
}
public static void setSessionObj(String id,Object obj){
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(id, obj);
}
Add them in your managed bean :