I use CDI to annotate beans. One bean called SessionManager holds the logined user information with the declaration:
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.ejb.Stateful;
#Stateful
#Named
#SessionScoped
public class SessionManagerImpl implements SessionManager, Serializable {
...
public UserDto getLoginedUser() {
...
}
}
And the other is called DashboardController as:
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.inject.Inject;
#Named
#RequestScoped
public class DashboardController implements Serializable {
#Inject
private SessionManager sessionManager;
...
public void loadUserInfo() {
...
UserDto userDto = sessionManager.getLoginedUser();
}
}
The first time i open a page refer DashboardController, it works well. And if i continue to use the website, it still works. But if i don't click any page for some minutes, and come back to open the page, it will display a null pointer for the javassist$$getLoginedUser method invocation (sessionManager is not null when i use debug to watch). The session is still valid for i can get values from session map directly using faces context.
What's wrong with the SessionManager? Thanks.
This occurs because your Stateful Session Bean (EJB) has passivated, and is not reintroduced to your session. If there isn't a strong need to make your session scoped object a session bean, I would just make it a SessionScoped managed bean.
Related
I have two managed Java beans:
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.ws.rs.Path;
#Path("/sync")
#ManagedBean(name="syncService", eager=true)
#ApplicationScoped
public class SyncService {
#ManagedProperty(value="#{ldapDirectoryAccess}")
private DirectoryAccess directoryAccess;
public void setDirectoryAccess(DirectoryAccess directoryAccess) {
System.out.println("SyncService.setDirectoryAccess()");
this.directoryAccess = directoryAccess;
}
public SyncService() {
System.out.println("SyncService() - constructed: " + this);
}
#PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
...
}
#ManagedBean(name="ldapDirectoryAccess", eager=true)
#ApplicationScoped
public class LdapDirectoryAccess implements DirectoryAccess {
public LdapDirectoryAccess() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
...
}
When I deploy the application in Tomcat, I get the following output in catalina.out:
SyncService() - constructed: ...SyncService#705ebb4d
...
LdapDirectoryAccess constructed: ...LdapDirectoryAccess#3c1fd5aa
SyncService.setDirectoryAccess()
DirectoryAccess injected: ...LdapDirectoryAccess#3c1fd5aa in:
...SyncService#705ebb4d
LdapDirectoryAccess constructed: ...LdapDirectoryAccess#59d6a4d1
So, first an instance of each bean is constructed as expected, and the second bean is injected into the first. But then, another instance of the second bean class is created. How is this possible? In this tutorial I found the following:
#ApplicationScoped
Bean lives as long as the web application lives. It gets created upon
the first HTTP request involving this bean in the application (or when
the web application starts up and the eager=true attribute is set in
#ManagedBean) and gets destroyed when the web application shuts down.
So I would expected that one instance of each bean is created when the application is started, and that both instances are destroyed when the application is shut down. But LdapDirectoryAccess is constructed twice.
Moreover, when I open the page that is served by SyncService I see:
SyncService() - constructed: ... SyncService#1cb4a09c
so a second instance of SyncService is built as well, and I cannot understand why. Also, no directoryAccess property is injected this time, and the service throws a null pointer exception.
This means that the first instance of SyncService is built correctly, but then
A second instance of SyncService is created (why?)
No LdapDirectoryAccess is injected into it (why?)
This second instance of SyncService is used to serve the call to my REST API. Why this instance and not the first one that was created?
I have looked at this question and its answers, however:
I am using Mojarra 2.2.18
My application's web.xml does not contain any tag mentioning com.sun.faces.config.ConfigureListener
So I after several hours investigation I am completely out of ideas. Do you have any hints?
A second instance of SyncService is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
JAX-RS, via #Path
JSF, via #ManagedBean
So, in effects, you have one instance of SyncService which is managed by JAX-RS, and you have another instance of SyncService which is managed by JSF, and only in this instance, the also JSF-specific #ManagedProperty is recognized. JAX-RS doesn't understand the #ManagedProperty and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's #javax.enterprise.context.ApplicationScoped. In legacy Java EE 6/7, you could abuse EJB's #javax.ejb.Singleton for that.
Given that you're still using the deprecated #ManagedBean instead of its replacement #Named, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
#Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
#PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
#Path("/sync")
public class SyncResource {
#EJB
private DirectoryAccess directoryAccess;
#PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
#ManagedBean
#RequestScoped
public class SyncBacking {
#EJB
private DirectoryAccess directoryAccess;
#PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService to eagerly initialize during server's startup, add the #javax.ejb.Startup annotation.
See also:
Inject an EJB into JAX-RS (RESTful service)
JSF Controller, Service and DAO
Backing beans (#ManagedBean) or CDI Beans (#Named)?
How to choose the right bean scope?
I am new to jsf and using JSF 2.0 to keep user information in a session scoped bean. I need to access this information across other beans for grunt work. Presently, this is how i am doing:-
private UserBean myuser1 = (UserBean)FacesUtils.getManagedBean("UserBean");
and then access properties as
if (myuser1.getUserType == 1) ...
this works but some time throws Argument Error: parameter key is null exception. I have been using following method too:-
private UserBean myuser2 = new UserBean();
if (myuser2.getUserType == 1) ...
In second method, my understanding is that if UserBean is already created in session, it would be retried. There are lots of question about 'how to access one bean in another' so i am confused. Please tell me one clean method which should always work and not throw null pointer exception abruptly.
The simplest way I know of is using #ManagedProperty, I don't know what you mean by safest though.
Let's say this is your sessionScoped bean :
#ManagedBean
#SessionScopped
public class UserBean {
//bean attributes and methods
}
Then you can access it in any other bean (provided it has the same or a narrower scope) as an attribute like this :
#ManagedBean
#ViewScoped //in this cas you can use SessionScoped, FlowScoped, or RequestScoped too
public class AnotherBean {
#ManagedProperty("#{userBean}")
UserBean userB;
//rest of the bean
//be sure to add getters and setters for the injected bean
}
For more details check this
Hope this helps.
Actually,
parameter key is null exception: it's either you didn't initialize the object witch can be solver with either adding
object = new Object(); // in the constructor of the class.
The second problem may be that the object is " DETACHED " you need to call the object using the method merge (with the entity manager).
A detached object is a known value but the JPA system doesn't know if it is the latest version from the DB or even sometimes the id value is not set for some reason (Not managed with jpa in other words it can be your case).
If em is your entity manager and you have the following function:
public Object latestVersion(Object o){ em.merge; }
In your Bean with:
#EJB
Service service;
if you do em.latestVersion(o); the problem of detached object is solved.
And for the real answer:
To access a object from another view you can simply do the following.
#ManagedBean
#SessionScoped
..... Bean1 {
public static Object o;
.....
}
#ManagedBean
..... Bean 2 {
private Object b=Bean1.o;
.....
}
Good luck
The standard practice of setting dependency of a scoped bean in another scoped bean is to use #Inject annotation like
#Inject UserBean userBean; in the bean you want use the UserBean object.
Your UserBean should be a stateful one.
#Stateful
#LocalBean
public class UserBean
{
private String name;
public String getName() { return name; }
public void setName( String name_ ) { name = name_; }
}
And just inject it into a stateless bean to modify its state:
#Stateless
#LocalBean
public class MyStatelessBean
{
#EJB
private UserBean userBean;
public String getUserName() { userBean.getName(); };
public void setUserName( String name_ ) { userBean.setName( name_); }
}
Or you can access it from (not wider scoped) managed beans as well in the same way:
#ManagedBean
#Dependent
public class MyJSFManagedBean
{
#EJB
private UserBean userBean;
}
You wrote in your comment you does not use EJBs at all. The picture modify like this:
The UserBean should be a SessionScoped CDI bean
#Named
#SessionScoped
pubilc class UserBean
{}
The othe CDI bean should be in a nearer scope:
#Named
#Request // or #ViewScoped or #Dependent
public class OwnerBean
{
#Inject
UserBean userBean;
}
The container automatically takes care to create the beans in the right scope and insert them into the owers (any kind of container managed objects : servlets, filters, action listeners, JSF/CDI beans). You need to insert a wider scoped resource into a thinner scoped one.
I'm beggining with Hibernate Envers. I'm already able to properly annotate classes with #Audited and create revisions, but I'm unable to record logged user data with my revisions.
My JSF 2.0 test application is running on CDI, JPA/Hibernate in a jbossEAP6 / wildfly server. I'm neither using Spring or Seam.
Here is some code:
revisionEntity.java
#Entity
#RevisionEntity(AuditListener.class)
public class RevisionEntity {
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long timestamp;
private String username;
LoginBean.java
#Named
#Stateful
#SessionScoped
public class LoginBean implements Serializable{
private String username;
...
AuditListener.java
import javax.ejb.Stateful;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.envers.RevisionListener;
import br.test.login.filterlogin.beans.LoginBean;
#Named
#Stateful
#SessionScoped
public class AuditListener implements RevisionListener {
#Inject
private LoginBean loginBean;
public void newRevision(Object revisionEntity) {
RevisionEntityEx RevEntity = (RevisionEntityEx) revisionEntity;
RevEntity.setUsername(loginBean.getUsername());
}
The loginBean injection fails, giving me a NullPointerException. Any ideas?
Sorry about my terrible grammar.
Regards,
Marcelo.
The listener is not managed by the container so your loginBean will not be injected.
We need to lookup for it...
Notice that UsuarioService should be changed to your type: LoginBean.
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
BeanManager beanManager = CDI.current().getBeanManager();
Bean<UsuarioService> bean = (Bean<UsuarioService>) beanManager.getBeans(UsuarioService.class).iterator().next();
CreationalContext<UsuarioService> context = beanManager.createCreationalContext(bean);
this.usuarioService = (UsuarioService) beanManager.getReference(bean, UsuarioService.class, context);
You didn't give any stacktrace, so I'm guessing. AFAIK you cannot combine together both
#Stateful
#SessionScoped
Because the first annotation is for making a class an EJB stateful session bean, but the second one is for making class a CDI managed bean, with scope Session.
It seems to me that you are trying to use technologies you don't understand at all. Please read a specification or at least some CDI tutorials/ sample GitHub projects.
Personal advice: most of the time you should prefer to use #Stateless over #Stateful for EJB beans. Then all data related to HTTP session you can store e.g. in some additional #SessionScoped CDI bean.
#ManagedProperty("#{sessionBean}") is not injected properly. The sessionBean is declared in a JAR file and it has a JSF 2.0 compatible faces-config as well.
But when I use
FacesContext context = FacesContext.getCurrentInstance();
sessionBean = (SessionBean) context.getApplication().evaluateExpressionGet(context, "#{sessionBean}", SessionBean.class);
It evaluates the session bean correctly. What is the reason?
EDIT: The bean that I want to be injected(sessionBean) is in a JAR file which is annotated as #ManagedBean and #SessionScoped. Also the JAR contains a JSF2 compatible faces-config in the META-INF/resources
1.) Where are you injecting the sessionBean into? Show us the class definition. Is the class a #ManagedBean?
2.) Check if the setter setSessionBean(SessionBean sb) called.
3.) Is the provided value in the setter null?
4.) You can also try to do the following:
#PostConstruct
private void init() {
FacesContext context = FacesContext.getCurrentInstance();
sessionBean = (SessionBean) context.getApplication().evaluateExpressionGet(context, "#{sessionBean}", SessionBean.class);
}
... and check if the sessionBean is evaluated correctly.
For me this was an issue with packages, the following imports worked for me:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
Before I was using a combination of different packages (auto-imported by IDE):
import javax.faces.bean.ManagedProperty;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
I'm probably really close to the solution but I'm new with JSF and I don't see my mistake.
I have a first SessionScoped Managed Bean that represents Business information (address, website, ...)
#Named(value = "businessController")
#SessionScoped
public class BusinessController implements Serializable {
private Business current;
#EJB private BusinessFacade ejbFacade;
....
I have a second SessionScoped Managed Bean that represents the logged in user
#Named(value = "loginController")
#SessionScoped
public class LoginController implements Serializable {
private Login current;
#EJB
private LoginFacade ejbFacade;
#ManagedProperty(value="#{businessController}")
private BusinessController businessController;
public BusinessController getBusinessController() {
return businessController;
}
public void setBusinessController(BusinessController businessController) {
this.businessController = businessController;
}
When a user logs in, I set the current attribute from the loginController
Depending on this current user, I want to set the business attribute from the businessController :
businessController.setCurrent(current.getBusiness());
My problem is that the businessController attribute is null !
I use NetBeans 7.0.1 and GlassFish 3.1
In debug mode, I can see a viewId variable with the value
>No current context (stack frame)<
Unfortunately it doesn't ring any bell to me.
Any help would be appreciated
Thanks
You are mixing JSF managed beans with CDI managed beans.
Your BusinessController is annotated with the CDI annotaion #Named but gets injected with the #ManagedProperty annotation (from JSF). CDI managed beans need to be injected with #Inject. No getter or setter needed in this case. If you tend to use CDI, make sure that you import the correct #SessionScoped:
CDI: javax.enterprise.context.SessionScoped
JSF: javax.faces.bean.SessionScoped
Try the following (After making sure to have the correct scope class imported):
#Inject private BusinessController businessController;