1

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?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ChrisM
  • 235
  • 5
  • 13

1 Answers1

3

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for the explanation BalusC, PostConstruct worked, but I needed to mark the EJB as transient, otherwise I would get an java.io.NotSerializableException. Most likely the cause is that EntityManager is not serializable. I had tried PostConstruct previously and no exception is thrown if using RequestScoped. Only when using ViewScoped will you get the NotSerializableException. – ChrisM May 20 '13 at 23:04
  • This shouldn't have been mandatory. Apparently there's something more broken in your design. Which class exactly is it which is been mentioned in the `NotSerializableException` message? – BalusC May 21 '13 at 00:34
  • Thanks for the heads up. There was something more broken, so I stripped the project down to investigate and found the cause to be the context parameter javax.faces.STATE_SAVING_METHOD set to client. I had the response buffer overflow (>2KB) problem described in http://stackoverflow.com/a/8072445/1754901 and used suggestion #5 which solved that problem, but now caused the NotSerializableException. So I have removed javax.faces.STATE_SAVING_METHOD, and put in place suggestion #4 instead (set to 64KB). Now all exceptions have gone and no need for transient. – ChrisM May 21 '13 at 14:00
  • Thanks BalusC. EJB's now inject properly and can be used during Managed Bean construction via PostConstruct. – ChrisM May 21 '13 at 14:02
  • State saving method shouldn't matter for EJBs as they are injected as serializable proxies. Again, which class exactly is it which is been mentioned in the `NotSerializableException` message? Isn't it just the view scoped managed bean itself? – BalusC May 21 '13 at 14:03
  • I have put State saving method back and the exception returns. No class of mine is mentioned in the stack trace. Just java.io.NotSerializableException: com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate. – ChrisM May 21 '13 at 14:17