Search code examples
jsfconstructornullpointerexceptionejbmanaged-bean

NullPointerException while trying to access @EJB bean in managed bean constructor


I've an EJB service.

@Stateless
public class SomeService {}

I'd like to inject this in a viewscoped bean and initialize with it:

@ManagedBean
@ViewScoped
public class ViewBean implements Serializable {

    @EJB
    private SomeService someService;

    public ViewBean() {
        System.out.println(someService.getEntity());
    }

}

However, it throws the following exception:

com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: com.example.ViewBean.
    at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:193)
    at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:102)
    at com.sun.faces.mgbean.BeanManager.createAndPush(BeanManager.java:409)
    at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:269)
    at com.sun.faces.el.ManagedBeanELResolver.resolveBean(ManagedBeanELResolver.java:244)
    at com.sun.faces.el.ManagedBeanELResolver.getValue(ManagedBeanELResolver.java:116)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    [snip]
Caused by: java.lang.NullPointerException
    at com.example.ViewBean.<init>(ViewBean.java:42)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at java.lang.Class.newInstance0(Class.java:374)
    at java.lang.Class.newInstance(Class.java:327)
    at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:188)
    ... 62 more

How is this caused and how can I solve it?


Solution

  • In other words, you're expecting that EJB injection works under the covers as follows:

    ViewBean viewBean;
    viewBean.someService = new SomeService(); // EJB injected, so that constructor can access it.
    viewBean = new ViewBean(); // ViewBean constructed.
    

    However, this is technically impossible. It's not possible to assign an instance variable when the instance isn't been constructed at all.

    The canonical approach to perform a task based on injected dependencies directly after construction is to use a @PostConstruct annotated method.

    So, to fix your concrete problem, just replace

    public ViewBean() {
    

    by

    @PostConstruct
    public void init() { // Note: Method name is fully free to your choice.
    

    This way the process would under the covers be roughly as follows:

    ViewBean viewBean;
    viewBean = new ViewBean(); // ShiftBean constructed.
    viewBean.someService = new SomeService(); // EJB injected.
    viewBean.init(); // PostConstruct invoked.
    

    Please note that the concrete problem has completely nothing to do with the view scope. You'd have had exactly the same problem when using a request, session or application scoped bean. This is thus another evidence that you have never actually excluded it from being the cause by testing using a different scope.