Crx
Crx

Reputation: 230

Referencing a CDI Bean in a non managed CDI Bean

Is it possible to obtain an instance of a CDI bean inside a class that is created using the new keyword? We're currently making some enhancements on an old application, and we're always getting a ContextNotActiveException everytime we do a programmatic lookup on CDI Singleton beans in our app.

Code for obtaining a reference:

public class ClassCreatedWithNew{
     public void doSomething(){
         MySingletonBean myBean = BeanManagerSupport.getInstance().getBean(MySingletonBean.class);
     }
}

BeanManagerSupport.java

public class BeanManagerSupport {

    private static final Logger LOG = Logger.getLogger(BeanManagerSupport.class);

    private static final BeanManagerSupport beanManagerSupport = new BeanManagerSupport();

    private BeanManager beanManager;

    private BeanManagerSupport() {
        try {
            beanManager = InitialContext.doLookup("java:comp/BeanManager");
        } catch (NamingException e) {
            LOG.error("An error has occured while obtaining an instance of BeanManager", e);
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) {
        Iterator<Bean< ? >> iter = beanManager.getBeans(clazz).iterator();

        if (!iter.hasNext()) {
            throw new IllegalStateException("CDI BeanManager cannot find an instance of requested type " + clazz.getName());
        }

        Bean<T> bean = (Bean<T>) iter.next();

        return (T) beanManager.getContext(bean.getScope()).get(bean);
    }

    public static BeanManagerSupport getInstance(){
        return beanManagerSupport;
    }
}

Upvotes: 4

Views: 1776

Answers (2)

R...
R...

Reputation: 2570

if you use new you have to have a constructor and initialize your dependencies manually and any logic that depends on them in a @PostConstruct method. Instead you can use CDI.current() e.g.

 MyService service = CDI.current().select(MyService.class).get(); 

then you can invoke all your service methods.

Upvotes: 0

struberg
struberg

Reputation: 730

There are 2 possible solutions.

  1. If you have a JavaEE-7 container then you can use CDI.current().get(MySingletonClass.class);

  2. If you have a JavaEE-6 container or even a Java SE application then you can use Apache DeltaSpike BeanProvider. It tries to lookup the BeanManager from JNDI but also does other tricks which also work if you don't have a full EE container. E.g. in SE and unit test.

You also need to take care that not only the container got booted but also that the Contexts did properly get activated. This is usually done via a ServletListener. If you are in an EE container then they register it for you. If you are using plain tomcat, jetty, etc then you need to activate it yourself.

See this example from Apache OpenWebBeans.

Upvotes: 2

Related Questions