简体   繁体   中英

Singleton CDI @Inject null pointer exception

I need to fire events from some ejb (Stateless and Singleton) using dependency injection. I do not use Spring, Guice etc. The problem is that I get NPE in one of beans when calling its method through getInstance(). Here is the code snippet:

@Stateless
@LocalBean
public class ControllerStartStop {
    @Inject
    private Event<SomeWebMessage> webEvent; 

    public String startCircle(String passwordP, String passwordH) {
    .........
    String res = "some msg";
    webEvent.fire(new SomeWebMessage(res, 0));   // this works fine
    MainDay.getInstance().startDay();      // NullPointerException

Here is MainDay singleton:

@Singleton
public class MainDay {
    private static final MainDay mDay = new MainDay();
    public static MainDay getInstance() {   return mDay ;   }

    @Inject
    private Event<SomeWebMessage> webEvent; 

    public void startDay() {
        String s = new String("MainDay");
        webEvent.fire(new SomeWebMessage(s,0));   // NullPointerException

beans.xml is in META-INF:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">

</beans>

There is no NPE when I fire event from a call of static method like MainDay.initDS() or when method startDay() is invoked by a Sheduler ( @Schedule(hour = " ", minute = " ", second = " /10")*. I have no idea what is the reason

Note that @Singleton means that the container (EJB or CDI, depends on which annotation it is) will manage the instance, ie you shouldn't create it yourself.

If you create the instance via private static final MainDay mDay = new MainDay(); there won't be any injection by the container and thus webEvent will be null. Besides that the container won't know about that instance and using @Inject MainDay somewhere else is very likely to produce another instance.

Thus just use inject (or lookups if you need to) directly:

class ControllerStartStop  {
  @Inject
  private MainDay mDay;

  ...
  public String startCircle(String passwordP, String passwordH) {
    ...
    String res = "some msg";
    webEvent.fire(new SomeWebMessage(res, 0)); 
    mDay.startDay();    
    ...
  }

There is no NPE when I fire event from a call of static method like MainDay.initDS() or when method startDay() is invoked by a Sheduler (@Schedule(hour = "", minute = "", second = "/10")*. I have no idea what is the reason

Without knowing your code it's only a guess but I'd assume you're injecting MainDay here or using a CDI/JNDI lookup. Hence the container will create an instance if there is none and will inject the Event objects.

NPE 1:

Shouldn't the targetted EJB MainDay "observe" the event and call its startDay() method?

public void onEvent(@Observes SomeWebMessage event) {
    // if (...)
        startDay();
}

So there is no need for a static getInstance() method.

NPE 2:

@Inject Event<SomeWebMessage> webEvent; 

Dependency injection (DI) only works, if you do not manually call the constructor new MainDay() but inject instances of the wanted bean and let the DI container handle construction.

But with @Observes (javax.enterprise.event.Observes) you should be able to remove all the smelly static stuff anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM