#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;
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'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.
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.
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;
Ok here is my session bean. I can always retrieve the currentUser from any Servlet or Filter. That's not the problem The problem is the fileList, and currentFile. I've tested with simple int's and Strings and its' the same effect. If I set a value from my view scoped bean I can get the data from another class.
#ManagedBean(name = "userSessionBean")
#SessionScoped
public class UserSessionBean implements Serializable, HttpSessionBindingListener {
final Logger logger = LoggerFactory.getLogger(UserSessionBean.class);
#Inject
private User currentUser;
#EJB
UserService userService;
private List<File> fileList;
private File currentFile;
public UserSessionBean() {
fileList = new ArrayList<File>();
currentFile = new File("");
}
#PostConstruct
public void onLoad() {
Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
String email = principal.getName();
if (email != null) {
currentUser = userService.findUserbyEmail(email);
} else {
logger.error("Couldn't find user information from login!");
}
}
Here is an example.
My view scoped bean. This is how it is decorated.
#ManagedBean
#ViewScoped
public class ViewLines implements Serializable {
#Inject
private UserSessionBean userSessionBean;
Now the code.
userSessionBean.setCurrentFile(file);
System.out.println("UserSessionBean : " + userSessionBean.getCurrentFile().getName());
I can see the current file name perfectly. This is actually being printed from a jsf action method. So obviously the currentFile is being set.
Now if I do this.
#WebFilter(value = "/Download")
public class FileFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
UserSessionBean userSessionBean = (UserSessionBean) session.getAttribute("userSessionBean");
System.out.println(userSessionBean.getCurrentUser().getUserId()); //works
System.out.println("File filter" + userSessionBean.getCurrentFile().getName()); //doesn't work
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
currentUser shows up fine but I can't see the file. It's just blank. The same thing happens with Strings, int's, etc.
Thanks for any help you can provide on this.
INFO: UserSessionBean : Line 3B--8531268875812004316.csv (value printed from view scoped bean)
INFO: File filter tester.csv (value printed when filter is ran.)
**EDIT**
This worked.
FacesContext context = FacesContext.getCurrentInstance();
userSessionBean = (UserSessionBean) context.getApplication().evaluateExpressionGet(context, "#{userSessionBean}", UserSessionBean.class);
I put this in the constructor of the ViewScoped and everything was fine. Now why isn't the inject doing what I thought? At first I thought maybe because I was using JSF managed beans instead of the new CDI beans. But I changed the beans to the new style(with named) and that was the same effect.
Does the inject only allow you to access the beans but not change their attributes?
You're mixing JSF and CDI. Your UserSessionBean is a JSF #ManagedBean, yet you're using CDI #Inject to inject it in another bean. CDI doesn't reuse the JSF managed one, it instead creates a brand new one. Use the one or the other, not both. The correct annotation to inject a JSF-managed bean is #ManagedProperty.
Replace
#Inject
private UserSessionBean userSessionBean;
by
#ManagedProperty(value="#{userSessionBean}")
private UserSessionBean userSessionBean;
and ensure that you don't have a import javax.enterprise.context anywhere in your code (which is the package of CDI annotations).
Alternatively, migrate all JSF bean management annotations to CDI bean management annotations.
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
#Named
#SessionScoped
public class UserSessionBean implements Serializable {}
import javax.inject.Named;
import javax.faces.view.ViewScoped;
#Named
#ViewScoped
public class ViewLines implements Serializable {}
Additional advantage is that you can just #Inject it inside a regular servlet or filter without the need to manually grab it as request/session/application attribute.
Moreover, JSF bean management annotations are deprecated since JSF 2.3. See also Backing beans (#ManagedBean) or CDI Beans (#Named)?
My best GUESS as to why this is happening, is because the variable file, is being set in view scope, and then passed by reference into the session scoped bean. Maybe this is happening because when the view scope bean is destroyed, it still has a reference to that variable, but doesn't bother to see if there's any other references to it in session scope, where it should be preserved. Hence, when it's destroyed, it's removed from both view and session scope in this case.
Could you try calling setCurrentFile with an object instantiated with 'new'? That might prove or disprove this hypothesis of mine.
Otherwise, my best advice would be to crack open the debugger, and see exactly where getCurrentFile is being changed.