0

I am using CDI 1.2 (Weld 2.3.5) and want to manually instantiate a bean and inject its dependencies during an AfterBeanDiscovery event listener. I'm expecting that this would allow me to ensure that its Initialization would precede the @PostConstruct initialization of other beans in the deployment container.

However, I am looking to use a bean declared via @Produces as a dependency for the bean I am trying to create. According to the BeanManager API doc, I am not allowed to call a BeanManager.getReference() method during the AfterBeanDiscovery event. So I find myself a little stuck; I'm not sure if/how I can retrieve/use a dependency declared in the container as a parameter when constructing my bean in my ABD listener.

So far, I have the following:

// Producer bean configuration

    @Produces
    @CustomConfigType
    public CustomConfig auditConfig() {
        CustomConfig config = new CustomConfig();
        config.setConfigFile("config/myconfig.properties");
        config.setDataSource(datasource);
        config.setResourceAccessor(new ClassLoaderResourceAccessor(getClass().getClassLoader()));
        return config;
    }


// CDI Extension

public class CDIBootstrap implements Extension {

    void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) {
        AnnotatedType<CDICustomConfig> at = bm.createAnnotatedType(CDICustomConfig.class);

        // this clearly fails as I am not allowed to use forEach() and retrieve an instance of the CustomConfig as declared using the @Produces annotation.  But my goal is to accomplish something like this            
  CDI.current().select(CustomConfig.class, new AnnotationLiteral<CustomConfigType>(){}).forEach(config -> {
            Bean instance = new Bean<CDICustomConfig>() {

                @Override
                public Set<Type> getTypes() {
                    Set<Type> types = new HashSet<>();
                    types.add(CDICustomConfig.class);
                    types.add(Object.class);
                    return types;
                }


                @Override
                public Class<? extends Annotation> getScope() {
                    return Dependent.class;
                }
                ...
                // Bolierplate methods
                ...
                @Override
                public Set<InjectionPoint> getInjectionPoints() {
                    return it.getInjectionPoints();
                }

                @Override
                public CDICustomConfig create(CreationalContext<CDICustomConfig> ctx) {
                    // I would like to use the @Produces bean reference here in the instance constructor
                    CDICustomConfig instance = new CDICustomConfig(config, config.getDataSource(), config.getResourceAccessor());
                    it.inject(instance, ctx);
                    it.postConstruct(instance);
                    return instance;
                }

                @Override
                public void destroy(CDICustomConfig instance, CreationalContext<CDICustomConfig> ctx) {
                    it.preDestroy(instance);
                    it.dispose(instance);
                    ctx.release();
                }
            };
            abd.addBean(instance);
        });
    }

I'm still learning how to best leverage the JEE/CDI events and listeners, so perhaps this is not the right approach. Is there anyway to legally do what I am hoping to do? Is there any way to use/access a CDI controlled bean instance from within the ABD event listener?

I'm looking to support multiple @Produces CustomConfig beans, and generate a CDICustomConfig for each instance of a CustomConfig bean found in the context. How should I approach this?

Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • Would you be so kind to describe why it is required to "to manually instantiate a bean and inject its dependencies during an `AfterBeanDiscovery` event listener." What goal you are trying to achieve? – Illya Kysil Nov 21 '18 at 21:46
  • You need to rethink your approach, why do you want that? What you are trying to do is not meant to work, `AfterBeanDiscovery` is too early for beans to exist. Soonest you can do that is `AfterDeploymentValidation`. – Siliarus Nov 26 '18 at 10:06
  • @IllyaKysil What I'm trying to achieve was modeled on the liquibase-cdi module. My goal was to manually create/instantiate a bean during the ABD event that would automatically get injected with all its dependencies. But as `@Siliarus` pointed out, I'm at at the right point in the lifecycle. In the end, I moved my bean to a method which `@Observes @Initialized(ApplicationScoped.class)` instead – Eric B. Nov 27 '18 at 23:36

0 Answers0