1

A singleton class is firing an Event but the container is not calling the CDI Event Listener.

Below, the creatData() in the DataLoaderSessionBean singleton class calls the loadUsers() method and in turn the loadUsers() is firing an event, which suppose to invoke XMLDataListener.UserData() but the call never happens. However, if I change the class from a Singleton to a Stateful or Stateless session bean then everything works well.

@Record
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)

public class DataLoaderSessionBean {

    @Inject
    @UserXMLData
    Event<DataEvent> userData;
    
    private final static int LOAD=0;

    private void loadUsers() {
        DataEvent event = new DataEvent();
        event.setCommand(LOAD);
        userData.fire(event);
    }
    
    @PostConstruct
    public void createData() {
        loadUsers();
        .........
    }
}

Here is the event listener. The userData() method on this event listener class is not being called by the container.

@Record
@SessionScoped
public class XMLDataListener implements Serializable {

    private static final long serialVersionUID = -2230122751970858111L;
    private final static int LOAD=0;
    public void UserData(@Observes @UserXMLData DataEvent event) {
        int cmd = event.getCommand();
        switch(cmd){
            case LOAD: loadUsers();
            break;
            ..........
            
        }
    }
}

The listener interface:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface UserXMLData {
}

The event data

public class DataEvent implements Serializable {
    
   private static final long serialVersionUID = -2230122751970857224L;
   private int command;

    public DataEvent() {
    }

    public int getCommand() {
        return command;
    }

    public void setCommand(int command) {
        this.command = command;
    }   
}

Any idea why this functionality works well for the session beans and not for the singleton?

Thanks

Darvin
  • 148
  • 8

1 Answers1

0

This is the required behaviour by the CDI 2.0 spec, section 10.5

If there is no context active for the scope to which the bean
declaring the observer method belongs, then the observer method
should not be called.

The @PostConstruct method of the singleton it's called on startup on the application context, so there is no session active. To trigger the observer method XMLDataListener should be declared annotated with @ApplicationScoped.

areus
  • 2,880
  • 2
  • 7
  • 17
  • Areus: Thanks for the reply. Does this also apply to the Interceptors? Because my Singleton class also has an Interceptor injection and it doesn't work. – Darvin Jan 26 '21 at 18:35
  • Interceptor are always in the `@Dependent` scope, so that's not the problem – areus Jan 26 '21 at 20:44
  • Thanks, so I kept the Singleton and move its logic to a new ApplicationScoped bean and have the lifecycle method PostConstruct in singleton to call the functionality in the ApplicationScoped bean. When the newly ApplicationScoped bean fires the event, the event listener is still not being invoked. Do I need to remove the Singleton all together from this picture? I prefer to keep the Singleton if possible because it's managed by the container, it automatically calls the respective lifecycle methods to load the initial application data. – Darvin Jan 27 '21 at 06:29
  • Adding an ApplicationScoped bean to fire de event doesn't change anything, the problem is that an event fired from the application context (either directly from the singleton, or in an application scoped bean) will not be observed by XMLDataListener because is on the session scope, and the session scope it's not active. It's the oberver that needs to be in a compatible scope – areus Jan 27 '21 at 09:24
  • Thanks for the response. If I understand you correctly, then I can directly fire an event from the lifecycle method of the Singleton class, if I change the listener to the ApplicationScoped? Let me try it out and let you know. – Darvin Jan 27 '21 at 11:07
  • Yes, changing the listener to ApplicationScoped worked with the Singleton. Thank you – Darvin Jan 27 '21 at 12:43