I wanted to know, is there any option to call a managed bean inside of EJB bean. Imagine, we have the code:
#ManagedBean
#SessionScoped
public class MyManagedBean implements Serializable {
public String getUrl() {
return "http://www.google.com";
}
}
#Stateless
public class MyEJB {
#ManagedProperty(value = "#{myManagedBean}")
MyManagedBean myManagedBean;
public void setMyManagedBean(MyManagedBean myManagedBean) {
this.myManagedBean = myManagedBean;
}
public void call() {
// NullPointerException here
System.out.println(myManagedBean.getUrl());
}
}
I also tried this:
#Stateless
public class MyEJB {
#EJB
MyManagedBean myManagedBean;
...
}
... but it returns different MyManagedBean instance.
This is not right. With CDI managed beans instead of JSF managed beans it's possible, but it is just not right as in, bad design. The business service should not be aware about the front-end at all. It makes the business service unreusable on other front-ends than JSF.
You should do it the other way round. You should inject the EJB in the managed bean, not the other way round. The EJB should be kept entirely stateless. You should just directly pass the EJB the information it needs as method argument (and never assign it as instance variable of EJB afterwards).
E.g.
#ManagedBean
#SessionScoped // <-- Did you read https://stackoverflow.com/q/7031885?
public class MyManagedBean implements Serializable {
private String url = "http://www.google.com";
#EJB
private MyEJB myEJB;
public void submit() {
myEJB.call(url);
}
public String getUrl() {
return url;
}
}
and
#Stateless
public class MyEJB {
public void call(String url) {
// No NullPointerException here.
System.out.println(url);
}
}
See also:
JSF Service Layer
Related
I have an EJB bean injected in a Managed Bean. Its constructor is called twice.
For example, I get:
com.logic.jsf.AdditionManagedBean created
com.logic.Addition$$$view45 created
com.logic.Addition created
I know #PostConstruct but I'm trying to understand why that happens. Is it because of proxy, and in that case shouldn't I see a proxy related literal in the printed name of the class?
#Stateless
#LocalBean
public class Addition{
public Addition(){
System.out.println(this.getClass().getName() +" created");
}
public String getAddition(){
return "Addition";
}
}
Injected in:
#ManagedBean
#RequestScoped
public class AdditionManagedBean {
#EJB
Addition addition;
public AdditionManagedBean(){
System.out.println(this.getClass().getName()+" created");
}
public String getAddition(){
return addition.getAddition();
}
}
I've the below managed bean
#ManagedBean
#RequestScoped
public class customerBean {
private Customer customer;
private CustomerJpaController customerJpa;
#PostConstruct
public void init() {
customer = new Customer();
}
public String addCustomer() throws Exception {
customerJpa.create(customer);
return "customer";
}
// getter and setter
}
The CustomerJpaController looks like below:
public class CustomerJpaController implements Serializable {
#PersistenceContext(unitName = "JFSCustomerPU")
private EntityManagerFactory emf = null;
private UserTransaction utx = null;
public CustomerJpaController(UserTransaction utx, EntityManagerFactory emf) {
this.utx = utx;
this.emf = emf;
}
// ...
}
When addCustomer() is invoked from the view, it throws java.lang.NullPointerException at line customerJpa.create(customer);. How is this caused and how can I solve it?
In your code sample, your CustomerJpaController is never instantiated. So, you get a null pointer exception.
I advise you to switch to CDI and rely on its injection method to have your entity manager (factory?) properly instantiated and injected in your controller when this last is instantiated. And, so, to use #Named instead of #ManagedBean.
So, you would have :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
...
}
(or whichever scope better fits your need)
It seems to me that you should use an EntityManager (EM) rather than an EntityManagerFactory (EMF) in your controller.
If your EMF is container managed and you have only one persistence unit, you can use the standard JPA #PersistenceContext annotation :
#PersistenceContext
private EntityManager entityManager;
If your EMF is not managed, you can leverage the power of deltaspike JPA module (remember : deltaspike is good for you :-) ) and inject an EntityManager in your controller :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
#Inject
private EntityManager em;
}
This requires the implementation of an EntityManagerProducer class, which can have any name but must have one method annotated #Produces #RequestScoped returning an EntityManager and another one taking an EntityManager parameter annotated with #Disposes. Ex :
public class MyEntityManagerProducer {
#Inject
#PersistenceUnitName("myPU")
private EntityManagerFactory emf;
#Produces
#RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(#Disposes em) {
if (em.isOpen()) {
em.close();
}
}
Note the usage of #PersistenceUnitName("myPU"), the deltaspike annotation that will handle the instanciation of the EMF.
If you have multiple persistence units, as it is often the case in the real world, you can set them apart with qualifiers. To declare a qualifier, declare an #interface with the following annotations :
#Target({ FIELD, METHOD, PARAMETER, TYPE })
#Retention(RUNTIME)
#Documented
#Qualifier
public #interface MyQualifier {
}
Then, add this qualifier to all #Produces, #Disposes and #Inject, to allow CDI to decide which persistence unit / entity manager you are willing to use :
public class MyEntityManagerProducer {
#Inject
#PersistenceUnitName("myPU")
private EntityManagerFactory emf;
#Produces
#MyQualifier
#RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(#Disposes #MyQualifier em) {
if (em.isOpen()) {
em.close();
}
}
and in your controller :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
#Inject
#MyQualifier
private EntityManager em;
}
All this requires CDI. Configuring CDI is way beyond a short answer to your question. I use OpenWebBeans in all my projects. Weld is also very popular.
This is my understanding of things (it might not be 100% correct but it will give you a general idea) :
Where in your bean is your Service instantiated ? Nowhere. In other words customerJpa is null.
Starting a connection to a db weights a lot on resources. So instead of you instantiating different services by yourself and opening-closing connections, the container has a pool of services and give the free ones to whoever needs it (in your case your bean needs one). How do you ask the container to give you a service :
Annotate #EJB above your service:
#EJB
private CustomerJpaController customerJpa;
and I think you are missing #Stateless as well
#Stateless
public class CustomerJpaController...
It's advised to switch to #Named and #RequestScoped (the other package) instead of #ManagedBean. Then you can use #Inject to inject your service instead of #EJB.here you can read further on the subject.
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 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 :
I'm trying to do simple thing. Inject qualified String (or File) in CDI.
So I have a qualifier:
#Retention(RetentionPolicy.RUNTIME)
#Target({FIELD,METHOD,PARAMETER,TYPE})
#Qualifier
public #interface FilesRepositoryPath {}
I have a producer:
public class FilesRepositoryPathProducer {
#Produces
#FilesRepositoryPath
public String getRepositoryDirectory() {
return "path.taken.from.configuration";
}
}
And I'm trying to use it:
#ApplicationScoped
public class FilesRepository {
#Inject
public FilesRepository(#FilesRepositoryPath String filesDirectory) {
//Do some stuff
}
}
However, WELD cannot instantiate this bean. I am getting an exception:
org.jboss.arquillian.impl.event.FiredEventException: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001410 The injection point [field] #Inject private za.co.fnb.commercial.dms.file.FilesRepositoryBeanTest.repo has non-proxyable dependencies
I know String is unproxable, but why WELD wants to create a proxy? It has #Dependent scope, so AFAIK it shouldn't create proxy anyway. How can I make it work?
you need the default constructor
#ApplicationScoped
public class FilesRepository {
public FilesRepository() {
}
#Inject
public FilesRepository(#FilesRepositoryPath String filesDirectory) {
//Do some stuff
}
}