javadependency-injectioncdijboss-weldpicocli

Is there a way to @Inject the SeContainer/CDI instance itself?


Is there a way to inject the SeContainer itself?

I am working on a Picocli CLI application where I create the instances of the commands by using CDI. I do not want to depend on a specific CDI implementation, and I would like to achieve something like this:

@ApplicationScoped
public class PicocliCDIFactory implements CommandLine.IFactory {
    private final SeContainer container;

    @Inject
    public PicocliCDIFactory(SeContainer container) {
        this.container = container;
    }

    @Override
    public <K> K create(Class<K> cls) throws Exception {
        return container.select(cls).get();
    }

}

An instance of CDI<?> would also be fine.

I am currently using Weld and this fails with:

Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type SeContainer with qualifiers @Default
  at injection point [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject public com.example.project.PicocliCDIFactory(SeContainer)
  at com.example.project.PicocliCDIFactory.<init>(PicocliCDIFactory.java:0)

    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:397)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:312)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:159)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:181)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:552)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:65)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:63)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
    at org.jboss.weld.executor.CommonForkJoinPoolExecutorServices.lambda$wrap$0(CommonForkJoinPoolExecutorServices.java:70)
    at java.base/java.util.concurrent.ForkJoinTask$AdaptedInterruptibleCallable.exec(ForkJoinTask.java:1489)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

I also tried to inject an Instance<SeContainer>, but it is unresolvable.

I am aware that with Weld I can inject the WeldContainer, but again, I do not want to depend on a specific implementation of CDI like Weld.

The only solution I am seeing right now is using CDI.current() to obtain a CDI object and use it to create instances.

However, this static method does not seem super robust to me. What if there are multiple containers, and I want to make sure that my factory gets injected with the CDI object that has also been used to create it?


Solution

  • I just found out that you can inject the BeanContainer.

    "Any bean may obtain an instance of BeanContainer by injecting it."
    

    From there I can just call BeanContainer.createInstance() and use the Instance<Object> obtained to create my objects.