Search code examples
jsfejb

How to inject ApplicationScoped bean in Stateless bean?


I have Stateless bean that calls asynchronous operation. I would like to inject to this bean my another bean, which stores (or rather should store) running process status. Here is my code:

Processor:

@Stateless
public class Processor {

    @Asynchronous
    public void runLongOperation() {
        System.out.println("Operation started");
        try {
            for (int i = 1; i <= 10; i++) {
                //Status update goes here...
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
        }
        System.out.println("Operation finished");
    }

}

ProcessorHandler:

@ManagedBean(eager = true, name="ph")
@ApplicationScoped
public class ProcessorHandler implements RemoteInterface {

    public String status;

    @EJB
    private Processor processor;

    @PostConstruct
    public void init(){
        status = "Initialized";
    }

    @Override
    public void process() {
        processor.runLongOperation();
    }

    public String getStatus() {
        return status;
    }


}

Process method of ProcessHandler is bound to a button. I would like to modify status of ProcessHandler bean from inside of Processor, so I can display updated status to user.

I tried to use @Inject, @ManagedProperty and @EJB annotations, but without success.

I'm testing my soulution on Websphere v8.5 developed using Eclipse EE.


When added inject to Processor class...

@Inject
public ProcessorHandler ph;

I got error:

The @Inject java.lang.reflect.Field.ph reference of type ProcessorHandler for the <null> component in the Processor.war module of the ProcessorEAR application cannot be resolved.

Solution

  • You should never have any client-specific artifacts (JSF, JAX-RS, JSP/Servlet, etc) in your service layer (EJB). It makes the service layer unreusable across different clients/front-ends.

    Simply move private String status field into the EJB as it's actually the one responsible for managing it.

    @ManagedBean(eager = true, name="ph")
    @ApplicationScoped
    public class ProcessorHandler implements RemoteInterface {
    
        @EJB
        private Processor processor;
    
        @Override
        public void process() {
            processor.runLongOperation();
        }
    
        public String getStatus() {
            return processor.getStatus();
        }
    
    }
    

    Note that this won't work on a @Stateless, but on @Singleton or Stateful only for the obvious reasons.