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.
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.