How to programmatically inject a Java CDI managed bean into a local variable in a (static) method

32,663

Solution 1

To inject an instance of class C:

javax.enterprise.inject.spi.CDI.current().select(C.class).get()

This is available in CDI 1.1+

Solution 2

Use for instance this utility class. You basically have to obtain instance of BeanManager and than grab the bean you want from it (imagine something like JNDI lookup).

Update

You could also use CDI utility class offered in CDI 1.1

SomeBean bean = CDI.current().select(SomeBean.class).get();

Update 2

In CDI 2.0 you have to use BeanManager class for obtaining bean instances programatically.

Solution 3

@BRS

import javax.enterprise.inject.spi.CDI;

...

IObject iObject = CDI.current().select(IObject.class, new NamedAnnotation("iObject")).get();

With:

import javax.enterprise.util.AnnotationLiteral;

public class NamedAnnotation extends AnnotationLiteral<Named> implements Named {

     private final String value;

     public NamedAnnotation(final String value) {
         this.value = value;
     }

     public String value() {
        return value;
    }
}

Solution 4

The link suggested by @Petr Mensik is very useful. I am using the same code in my example.

Here is a way to get an instance of the class in instance methods/static methods. It is always better to code for interfaces instead of using the class name hard coded in the methods.

@Named(value = "iObject ")
@RequestScoped
class IObjectImpl  implements IObject  {.....}

//And in your method

IObject iObject = (IObject) ProgrammaticBeanLookup.lookup("iObject");
.........
//Invoke methods defined in the interface

This programmatic look up of beans can be quite useful when you have an application scoped object with method that requires an instance of a class that may change over time. So, it is always better to extract the interface and use programmatic bean look up for the sake of loose coupling.

Solution 5

You should include qualifiers:

List<Annotation> qualifierList = new ArrayList();
 for (Annotation annotation: C.class.getAnnotations()) {
   if (annotation.annotationType().isAnnotationPresent(Qualifier.class)) {
     qualifierList.add(annotation);
   }
 }
javax.enterprise.inject.spi.CDI.current()
   .select(C.class, qualifierList.toArray(new Annotation[qualifierList.size()])
   .get()
Share:
32,663
XDR
Author by

XDR

Updated on September 25, 2020

Comments

  • XDR
    XDR over 3 years

    How can I programmatically inject a Java CDI 1.1+ managed bean into a local variable in a static method?

  • XDR
    XDR almost 10 years
    Thanks for the suggestion. I actually found a simpler solution, which I'll detail in an answering post.
  • XDR
    XDR over 9 years
    Please see my new answer that shows how annotations can be used with the CDI methodology, which provides more versatile and typesafe lookups than ProgrammaticBeanLookup
  • phoenix
    phoenix over 9 years
    So, after writing an implementation class for IObject with Named annotation value iObject, we need to write an anonymous inner class to get an instance. Isn't this a bit more complicated than by simply look up and cast? Or please correct me if my understanding is wrong.
  • phoenix
    phoenix over 9 years
    Probably it would be the better if you can actually make it more readable by having the import and dividing one step into two steps. That way it becomes more readable.
  • XDR
    XDR over 9 years
    NamedAnnotation can be used for any @Named bean, not just IObjects. ProgrammaticBeanLookup takes more code than NamedAnnotation, but can only be used for Class or @Named String, whereas the CDI route can take in other annotations and/or a TypeLiteral. ProgrammaticBeanLookup also requires JNDI classes to be in the classpath, and manual population of a non-final static variable if it isn't. Moreover, BeanManager isn't guaranteed to be threadsafe, so ProgrammaticBeanLookup might have threading issues.
  • XDR
    XDR over 9 years
    You can always wrap the CDI usage in a helper method, such as <T> T getNamedBean(Class<T> clazz, String name)
  • jpangamarca
    jpangamarca about 9 years
    If you use CDI.current().select, you'll get an Instance<T>, don't forget to destroy it after using it.
  • TigerBear
    TigerBear over 8 years
    XDR, Your solution is working for me. I was trying a different way but couldn't get it working: context.getApplication().evaluateExpressionGet(context, "#{beanName}", BeanName.class) shouldn't they both work?
  • XDR
    XDR over 8 years
    @punchingInAPepper: I'm unfamiliar with the method that you mentioned, so, unfortunately, I can't answer your question.
  • TigerBear
    TigerBear over 8 years
    @XDR No worries, just thought it wouldn't hurt to ask. After searching for hours, this was the only solution that worked, It would be nice if there was more info on why. Do you have links to resources that helped you figure this out?
  • XDR
    XDR over 8 years
    @punchingInAPepper: I forget where I learned this. It might have been from the weld documentation: docs.jboss.org/weld/reference/latest/en-US/html
  • Dherik
    Dherik almost 7 years
    @jpangamarca destroy? Can you explain how?
  • Roland
    Roland over 6 years
    @jpangamarca maybe means null-ing it? Mostly you want to keep an instance of your backing bean (get() returned it) in your converter/validator for performance reasons (please look at the source code of CDI's methods). I usually do this with a static field in the converter/validator: private static MyFooBackingBean FOO_CONTROLLER; and later: if (null == FOO_CONTROLLER) { FOO_CONTROLLER = CDI.current().select(MyFooBackingBean.class).get(); } Maybe annotations are missing here.
  • jpangamarca
    jpangamarca over 6 years
    @Dherik Destroying a bean reference obtained from an injected Instance<T> is necessary to avoid memory leaks, please see weld.cdi-spec.org/news/2016/05/18/enhanced-instance
  • absmiths
    absmiths over 5 years
    The CDI class does this nicely in one easy step.
  • user2359997
    user2359997 over 4 years
    @XDR Thanks for the solution does this work with cdi2.0 ? i'm getting weld not initialized
  • XDR
    XDR over 4 years
    @user2359997 I haven't used CDI 2.0, but I imagine it should be backwards compatible with 1.1. I don't know about your weld issue, and I haven't used CDI or Java EE in years