Injecting @EJB into explicitly created object -> NullPointerException

1.6k views Asked by At

I am trying to figure out how object instantiation works in Java EE. I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through @EJB if the Class defining the member has been instantiated explicitly by me rather than the container. My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it. Can we make the container manage such objects?

Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?

@Stateless
public class ClassA {
    public void bar() {
        // Does something fun
    }
}

@Stateless 
public class ClassB {
    @EJB
    private ClassA A;

    public void foo() {
        A.bar(); // throws NullPointerException if ClassB 
                 // is explicitly instantiated works fine
                 // if injected with @EJB
    }
}

public class ClassC {
  //@EJB // Only way to go? Can we choose an implementation of ClassB?
    private ClassB B;

    public ClassC() {
        this.B = new ClassB(); // Bad idea? Possible??
        this.B.foo(); 
    }
}

The reason I'm looking in to it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?

2

There are 2 answers

3
ares On BEST ANSWER

I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through @EJB if the Class defining the member has been instantiated explicitly by me rather than the container.

This is obvious as the dependencies are injected by the container. So if you are creating the instance and not setting any value for the dependency, then the dependency will be null. On the other hand, when instances are created by the container, it also sets the values of its dependencies.

My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it.

Yes, that is correct. When you create the instance, the instance is therefore, not managed.

Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?

No, when you create the instance, the dependencies will be null.

The reason I'm looking into it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?

If you need to inject a specific implementation, the you can do that by specifying bean name.

@EJB(beanName="DefaultService")
private Service defautService;

@EJB(beanName="SpecificService")
private Service specificService;

Refer to this link: http://www.adam-bien.com/roller/abien/entry/injecting_different_implementations_into_an

Alternatively, if you're using CDI you can use @Qualifier

2
Steve C On

The other way to get an EJB reference if you cannot use injection is to use JNDI to look it up.

Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");

Therefore you can use whatever logic you need to determine the JNDI name of the actual ClassB implementation you need and then look it up.