2

I'm trying to dynamically retrieve a dependency for my Java code.

I know the class name, but I want to take the instance managed by the container, with proper indirect dependencies resolved.

For example:

class Foo {

    public static void foo() {
        Bar bar = (Bar) getDependency("com.example.Bar");
        bar.bar();
    }

}

class Bar {

     @Inject
     private Spam spam;

     public void bar() {
         spam.spam();
     }

}

I can't construct a Bar instance myself because I wouldn't be able to inject the correct Spam. So I want as if Foo had injected a Bar into it. I can't add a field like @Inject Bar bar because the exact name of the dependency varies in runtime.

Any way to do this?

I'm using WildFly 8.2.0.

Thiago Negri
  • 5,221
  • 2
  • 28
  • 39
  • 2
    *"because the exact name of the dependency varies in runtime."* What does it mean? The type may vary? If so then classes which can be injected can implement the same interface, then you can create `@Qualifier` with value unique for every class and `@Inject` desired implementation as an interface. What can come in handy is: [`Instance`](http://docs.oracle.com/javaee/6/api/javax/enterprise/inject/Instance.html) interface or [`@Produces`](http://docs.oracle.com/javaee/7/api/javax/enterprise/inject/Produces.html) annotation. – Geinmachi Jan 27 '16 at 14:05
  • That's right. The type varies. I will use a common interface to all of them. The problem is that I need a runtime information to know which "qualifier" to use. I can't say which dependency to use statically. – Thiago Negri Jan 27 '16 at 14:20
  • Let's say you have class `A` and `B` and `@MyImpl` qualifier which have `String` value. You annotate class `A` with `@MyImpl(value = "A")` and the same goes for B. When you use `Instance` interface you can use `select` method to find your implementation. If you want class `A` to be injected you say: "Give me object of class with `@MyImpl` qualifier and "A" value". Then the class `A` will be injected. "A" value may be a variable that vary at runtime. https://docs.jboss.org/weld/reference/latest/en-US/html/injection.html#_obtaining_a_contextual_instance_by_programmatic_lookup – Geinmachi Jan 27 '16 at 14:32

2 Answers2

1

You can do something like this:

public class Foo {

    @Inject BeanManager beanManager;

    public void foo() {
        Set<Bean<?>> beans = beanManager.getBeans(Bar.class);
        Bean<?> bean = beanManager.resolve(beans);
        CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
        Bar bar = (Bar) beanManager.getReference(bean, Bar.class, creationalContext);   
    }
}

or maybe even simpler:

public class Foo {

    @Inject Instance<Object> instance;

    public void foo() {
        Bar bar = instance.select(Bar.class).get();
    }
}
Xavier Dury
  • 1,530
  • 1
  • 16
  • 23
1

Here is the source code of the simple ManualContext class I've created for one of my projects. It was primarily designed for accessing CDI-managed beans from POJO objects, but maybe it could be helpful for you.

Example of use:

final ManualContext mCtx = new ManualContext();
...
final MyBean myBean = mCtx.lookupCDI(MyBean.class);  // obtains the CDI-managed instance
xwinus
  • 886
  • 3
  • 12
  • 28