A drawback of declarative design implementation

Hello!
I have a visual custom component which is quite complicated stuff itself and has its own model injections …
@Inject MyComponent mycomp;

I tried to put this component into a certain layout by Design.read(“ViewWithInjectedComponent.html”,this); and the outcomes were disappointed: the component did NOT appear. Then I traced the Design object with hope to shoulder the way by overriding something and revealed that there is no decent oportunity to sort out the porblem because everything is too tied…

Please, consider the possibility to work with instatiated components in future versions.
Thank you.
Anyway Vaadin is awesome)

The Design.read() injects the component references to the design root, so you can’t use CDI injection like that. If you want to have the CDI container manage the components, you need to implement a ComponentFactory and set it with Design.setComponentFactory().

I haven’t myself looked into how that would go; probably you need to use CDIUtil.getBeanManager() to get the bean manager and do JNDI lookup for the bean. There’s probably no documentation or examples for that, so I hope you can figure it out how to do that.

For sure, Marko, there could be possible workarounds… but, you know, it spoils the whole beauty that declarative design can bring to your project. Especially in a new one.
BTW, if I’m not mistaken, the ComponentFactory isn’t aware of the variable name (in terms of _id=“”) that it creates. Look:

private Component instantiateClass(String qualifiedClassName) {
        ComponentFactory factory = Design.getComponentFactory();
        Component component = factory.createComponent(qualifiedClassName, this);

        if (component == null) {
            throw new DesignException("Got unexpected null component from "
                    + factory.getClass().getName() + " for class "
                    + qualifiedClassName);
        }

        return component;
    }

Is that a problem with CDI? CDI also instantiates by class (and qualifiers), not by variable name.

I’m not quite sure if that can be helped in Designer – perhaps the CDI add-on could have some support for that, but it’s still a bit unclear to me how it should work. Perhaps some custom annotation to define the design for a design root class, such as a CDIView (but probably should be more generic). You could file a feature ticket for that, and suggest some API.

In any case, making a simple ComponentFactory that instantiates the beans with the BeanManager should allow simple generic use, but passing qualifiers and such to a generic ComponentFactory would probably be a mess.

Let’s see quickly…

@CDIView(value=HelpView.NAME)
@DesignRoot
public class HelpView extends VerticalLayout
                      implements View {
    public final static String NAME = "help";

    @Inject
    User user;

    // Will be "injected" from the design
    Label greeting;
    Button back;
    
    class MyCDIComponentFactory extends Design.DefaultComponentFactory {
        @Override
        public Component createComponent(String fullyQualifiedClassName,
                                         DesignContext context) {
            Class cls = resolveComponentClass(fullyQualifiedClassName, context);

            BeanManager beanManager = CDIUtil.lookupBeanManager();
            Set<Bean<?>> beans = beanManager.getBeans(cls, new AnnotationLiteral<Any>() {});
            if (beans.isEmpty())
                return super.createComponent(fullyQualifiedClassName, context);

            Bean<?> bean = (Bean<?>) beanManager.resolve(beans);
            if (bean == null)
                return super.createComponent(fullyQualifiedClassName, context);

            return (Component) beanManager.getReference(bean, cls, beanManager.createCreationalContext(bean));
        }
    }
    
    public HelpView() {
        Design.setComponentFactory(new MyCDIComponentFactory());
        Design.read("HelpView.html", this);

        // On click, navigate back to the main view
        back.addClickListener(e ->
            getUI().getNavigator().navigateTo(MainView.NAME));
    }
    
    @Override
    public void enter(ViewChangeEvent event) {
        greeting.setValue("Here is help for you, " + user.getName());
    }
}

Ah, hmm, a note: The ComponentFactory is really a global object, so setting it in the view object is really
not
what you should do. Probably you should set it in the servlet constructor or something like that.

“Is that a problem with CDI? CDI also instantiates by class (and qualifiers), not by variable name”
Of course not! I’ve expressed myself a bit clumzy. I ment that it might be possible to loop injected references down into the Design through a custom ComponentFactory… I suppose… I’m not sure it is really a way…

But anyway, I still don’t see the use of abandoning initialized class members… Really…
Does it matter which part of the environment creates them?
Design is more about parametrization (moreover, visual&hierarchical aspect of it) but not (ok, less) about creation, isn’t it?
About API. I’m a newbie in Vaadin and in Java in general. I’m trying to migrate from another ancient language.
I think I’m not experienced enough to contribute to such a wonderful framework. )
So I think the idea should be debated firstly.