Search code examples
javacdiweld

CDI Extension for stereotypes and proxied interfaces


I am defining a web-based generic configuration module for applications.

This is the scenario use case:

You have your application, that is highly configurable, so you define an interface to define the configurations for your application, and so you annotate the interface with @Config annotation.

@Config
public interface AppConfig{
  boolean isPropertySet();
  String getHeaderTitleLabel();
}

The @Config annotation is both a configuration provider marker and a CDI stereotype:

@Documented
@Inherited
@Retention(RUNTIME)
@Target({FIELD, PARAMETER, TYPE, METHOD})
@Qualifier
@Named
@SessionScoped
public @interface Config{
}

At application level (lets say CDI enabled jsf application)

@Named
@SessionScoped
public class MyController implements Serializable{
  @Inject
  @Config
  private AppConfig appConfig; 
}

On the config library, the user can get an instance of the AppConfig like:

AppConfig appConfig = ConfigManager.getInstance(AppConfig.class);

which resolves all requirements from the @Config annotation and environment variable and properties file, create a proxy and connect to a web service which will provide the necessary config data.

Currently, the working implementation is for the developer to define a producer field/method.

@Stateless
public class ConfigProducer{

 @Produces
 @Config
 public AppConfig getInstance(){
   return ConfigManager.getInstance(AppConfig.class);
 }
}

If you were to define several appconfigs based on different project modules, it may not be cumbersome but may cause a little inconvenience. I simply want my users to do the injection, the way they would do: @Inject EntityManager em;without recourse to how it is instantiated.

I have defined a CDI extension to register the implementation of AppConfig and enable it for injection.

public class ConfigExtension implements Extension{

 public void observeProcessAnnotatedType(@Observes ProcessAnnotatedType patEvent){}
 public void observerBeforeBeanDiscovery(@Observes BeforeBeanDiscovery bbdEvent){}
 public void observeAfterBeanDiscovery(Observes AfterBeanDiscovery abd){}
 public<T,X> void observeProcessInjectionPoint(@Observes ProcessInjectionPoint<T,X> pipEvent, BeanManager bm){}
 public<T,X> void observeProcessInjectionTarget(@Observes ProcessInjectionTarget<T,X> pipEvent, BeanManager bm){}

}

My current problem is which is the correct observer event to register the AppConfig implementation? I have looked at Bean and some of the most confusing parts are the

Bean.getBeanClass(); //should i return Proxy.getProxyClass() here?
Bean.getTypes(); //and here?
Bean.create(CreationalContext<T> cc); //at this point i need to return the proxy for AppConfig.class

When i do this currently, the weld implementation still complains of Unsatisfied Dependency.

I would appreciate help on how to go about this.


Solution

  • After reading the CDI specification, I have come to the conclusion that i do not have control over the instantiation of a contextual reference.

    This has been mentioned at section

    7.1. Restriction upon bean instantiation

    If the application requires more control over instantiation of a contextual instance, a producer method or field may be used.

    So in essence, i need to check other frameworks for what i want to do, or my users simply have to define their own producers for every AppConfig interface they declare.

    http://docs.jboss.org/cdi/spec/1.0/pdf/JSR-299-FD.pdf