How do I register a producer for subtypes dynamically?
dan.j.allen Apr 5, 2010 7:24 AMI'm trying to figure out how to register a producer method that will match injection points of any subtype of a particular class.
While the following is not legal, it depicts what I am trying to accomplish:
@Produces @ClientId
public <T extends UIComponent> T findComponent(InjectionPoint ip) { ... }I'll explain what is going on here. I want to look for any UIComponent in the current JSF UI component tree and return it. The @ClientId qualifier provides the search expression and the type determines the corresponding producer.
@Inject @ClientId("register") UICommand registerButton;The component returned by UIViewRoot#findComponent() will always descend from the base class UIComponent. However, I don't want to have to create a producer method for every possible type, because that is
- ridiculous
- a closed set
What I would rather do is scan the classpath for all descendants of UIComponent (or have some configuration files that list them out) and create a producer method that maps to that type. It's just that I can't figure out how to register the beans dynamically.
I figure I need to start with a producer that uses type parameters:
public class UIComponentProducer<T extends UIComponent>
{
@Produces @ClientId
public T findComponent(InjectionPoint ip) { ... }
}One approach is to observe AfterBeanDiscovery and register a reified bean for every UIComponent subtype based on the generic producer, but I still have to statically link to the types:
public void addUIComponentProducers(@Observes AfterBeanDiscovery e)
{
final Bean b = manager.getBeans(UIComponentProducer.class).iterator().next();
e.addBean(new Bean<UIComponentProducer<UIForm>>() {
public Set<Type> getTypes()
{
Set<Type> types = new HashSet<Type>();
types.add(new TypeLiteral<UIComponentProducer<UIForm>>() {}.getType());
return types;
}
public Set<Annotation> getQualifiers()
{
return b.getQualifiers();
}
public Class<? extends Annotation> getScope()
{
return b.getScope();
}
public String getName()
{
return b.getName();
}
public Set<Class<? extends Annotation>> getStereotypes()
{
return b.getStereotypes();
}
public Class<?> getBeanClass()
{
return UIComponentProducer.class;
}
public boolean isAlternative()
{
return b.isAlternative();
}
public boolean isNullable()
{
return b.isNullable();
}
public Set<InjectionPoint> getInjectionPoints()
{
return b.getInjectionPoints();
}
public UIComponentProducer<UIForm> create(CreationalContext<UIComponentProducer<UIForm>> creationalContext)
{
return new UIComponentProducer<UIForm>();
}
public void destroy(UIComponentProducer<UIForm> instance, CreationalContext<UIComponentProducer<UIForm>> creationalContext)
{
}
});
}Any idea how to do this registration dynamically? Because if I have to do all this, I might as well just create a producer class corresponding to every type.