Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the equivalent of @ManagedBean(eager=true) in CDI

As we all know that it is recommended to use annotations from javax.enterprise.context instead of javax.faces.bean as they are getting deprecated.

And we all found ManagedBeans with eager="true" annotated with @ApplicationScoped from javax.faces.bean and having a @PostConstruct method are very useful to do web application initialization e.g: read properties from file system, initialize database connections, etc...

Example :

import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.annotation.PostConstruct;

@ApplicationScoped
@ManagedBean(eager=true)
public class someBean{

    @PostConstruct
    public void init(){
        //Do all needed application initialization.
    }
    ...
}

What I want to know is how can I get the same behavior if I used annotations from javax.enterprise.context.

Note: @Startup annotation from javax.ejb will help to run that code but only at the moment of deployment of the webapp when the application server Starts.

like image 720
Jalal Sordo Avatar asked Jul 16 '16 14:07

Jalal Sordo


3 Answers

This is not provided by CDI or JSF. You could homegrow your own with a custom CDI qualifier and a ServletContextListener to hook on webapp start.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Eager {
    //
}

@WebListener
public class EagerListener implements ServletContextListener{

    private static final AnnotationLiteral<Eager> EAGER_ANNOTATION = new AnnotationLiteral<Eager>() {
        private static final long serialVersionUID = 1L;
    };

    @Override
    public void contextInitialized(ServletContextEvent event) {
        CDI.current().select(EAGER_ANNOTATION).forEach(bean -> bean.toString());
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // NOOP.
    }

}

(note: toString() triggers lazy instantiation)

import com.example.Eager;
import javax.enterprise.context.ApplicationScoped;

@Eager
@ApplicationScoped
public class YourEagerApplicationScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("Application scoped init!");
    }
}

As to existing libraries, only JSF utility library OmniFaces offers @Eager out the box.

import org.omnifaces.cdi.Eager;
import javax.enterprise.context.ApplicationScoped;

@Eager
@ApplicationScoped
public class YourEagerApplicationScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("Application scoped init!");
    }
}

It's also supported on @SessionScoped, @ViewScoped and @RequestScoped.

Regardless of the approach, the only disadvantage is that FacesContext isn't available at the moment the bean is constructed. But that shouldn't be a big problem, with CDI you can simply directly @Inject artifacts of interest such as ServletContext or HttpSession.

like image 194
BalusC Avatar answered Nov 14 '22 08:11

BalusC


As an alternative, you could use EJB instead of CDI. Then you can have a @Singleton with @Startup

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class SomeBean {

    @PostConstruct
    public void init(){
        //Do all needed application initialization.
    }
    ...
}
like image 29
gmanjon Avatar answered Nov 14 '22 08:11

gmanjon


CDI 1.1 also offers a standard way to observe scope lifecycle events, for instance:

public void processApplicationScopedInit(@Observes @Initialized(ApplicationScoped.class) ServletContext payload) {}
public void processApplicationScopedDestroyed(@Observes @Destroyed(ApplicationScoped.class) ServletContext payload) {}

For more information: http://www.next-presso.com/2014/06/you-think-you-know-everything-about-cdi-events-think-again/

like image 2
Stéphane Appercel Avatar answered Nov 14 '22 09:11

Stéphane Appercel