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.