1

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?

Christian Eriksson
  • 2,038
  • 2
  • 22
  • 28
  • You cannot instantiate an Ejb with 'new' keywords, that's not an option. To refer an ejb class you either made the container injects or you look up via JNDI. Each choice has its meaning, which is you use on or the other approach depending on the context. – Leonardo Jan 07 '17 at 09:18

2 Answers2

2

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

ares
  • 4,283
  • 6
  • 32
  • 63
  • If i annotate a class to be an **EJB** but doesn't inject it anywhere and instantiate it in **JPQL** for **DTO Projection** (Hibernate), Is the class **container managed bean**? – Arash Nov 26 '19 at 21:11
  • 1
    If you inject the bean it would be container managed. If you instantiate it using the new keyword, it would not be container managed. – ares Nov 27 '19 at 06:23
  • Thanks ares, I thought the **Hibernate** converts the class to the **managed bean** . – Arash Nov 27 '19 at 07:19
0

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.

Steve C
  • 18,876
  • 5
  • 34
  • 37
  • That's pretty neat, I'll absolutely try it out and have a read about JNDI I believe! I also found [this answer](http://stackoverflow.com/a/7923159/2671179) to a similar question. Would you care to comment on the differences between the approaches. That is, what considerations should I have using JNDI vs a \@singleston \@startup "producer class"? – Christian Eriksson Jan 07 '17 at 13:42
  • JNDI lookup is the "old fashioned" way to get access to EJBs, DataSources, etc. In general it's a PITA because you have to handle exceptions and type cast the result correctly. You would only use JNDI if there is no option to use container injection (which is pretty much never in a Java EE 7 runtime). – Steve C Jan 07 '17 at 23:37