Basit
Basit

Reputation: 8626

EJB method is not calling from constructor

I created an ejb

@Stateless
@LocalBean   
public class BasitBean {

    public String helloBasit() {

        return "Basit";

    } //end of helloBasit()

} //end of class BasitBean

I am calling it from JSF like

<h:body>

    <h:outputLabel value="#{helloBasit.callBasit()}" />

</h:body>

@ManagedBean
@SessionScoped
public class HelloBasit {

    @EJB
    private BasitBean basitBean;

    /** Creates a new instance of HelloBasit */
    public HelloBasit() {         

    }

    public String callBasit() {

        return basitBean.helloBasit();

    } //end of callBasit()

} //end of class HelloBasit

This code is working fine. But when i change the code like this

<h:body>
    <h:outputLabel value="#{helloBasit.label}" />        
</h:body>

@ManagedBean
@SessionScoped
public class HelloBasit {

    @EJB
    private BasitBean basitBean;
    String label;

    /** Creates a new instance of HelloBasit */
    public HelloBasit() {

        System.out.println();
        String label = basitBean.helloBasit();
        System.out.println(label);

    }

    public BasitBean getBasitBean() {
        return basitBean;
    }

    public void setBasitBean(BasitBean basitBean) {
        this.basitBean = basitBean;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

} //end of class HelloBasit

Then i get the exception

SEVERE: Error Rendering View[/index.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: pk.mazars.basitMahmood.HelloBasit.
 at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:193)
 at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:102)
 ......

Why i am getting this exception? The flow should be what i understand is when my page encounters #{helloBasit.label} then my constructor get call, instance variable get initialized, injected the bean instance into the basitBean, then the bean method should call. But i am getting null in the bean instance in this case why? Why previous code is working and it is not ? How can i call bean from the constructor ?

Thank you.

Upvotes: 2

Views: 4986

Answers (2)

Daniel
Daniel

Reputation: 37071

try to move your content of the constructor into a post constructor instead...

like this

@PostConstruct
private void init() {
    System.out.println();
    String label = basitBean.helloBasit();
    System.out.println(label);
}

Cause the ejb bean should be injected only after the managed bean has been initiated

The @PostConstruct is being run after the constructor (after that the managed bean itself was created by the JSF) and only then the EJB is being injected into the bean and can be accessed...

Upvotes: 7

rbento
rbento

Reputation: 11678

Your idea is correct, but I see some things that may be fixed.

  • @LocalBean annotation is not required if your EJB is not directly implementing an interface. In this case, with or without the @LocalBean annotation you have the same effect. You may leave that if you want to make it explicit though. See this.

  • Make sure both @ManagedBean and @SessionScoped import from javax.faces.bean package.

Please, see this working sample:

EJB

import javax.ejb.Stateless;

@Stateless
public class PersonService { 

    public String getName() {
        return "Cloud Strife";
    }
}

Managed Bean

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class PersonBean {

    @EJB
    private PersonService ps;

    private String name;

    @PostConstruct
    public void init() {
        name = ps.getName();
    }

    public String getName() {    
        return name;
    }
}

XHTML Page

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">

    <f:view contentType="text/html">
        <h:head>
            <title>Test</title>
        </h:head>
        <h:body>
            <h1>Welcome, #{personBean.name}</h1>
        </h:body>
    </f:view>

</html>

If your value should be loaded only once, say at your bean construction, always prefer a method with @PostConstruct annotation instead of the constructor.

Also, in order to call bean methods before rendering a view you could use a f:event tag, for example:

<f:event type="preRenderView" listener="#{personBean.init}" />

I hope it helps!

Upvotes: 0

Related Questions