Search code examples
springdependency-injectionvaadinvaadin7vaadin4spring

No qualifying bean of type found for dependency, vaadin


I got No qualifying bean of type [com.vaadin.ui.HorizontalLayout] found for dependency error when I try to inject argument from another config file like this: Main Config:

@Configuration
@EnableVaadin
@Import(NavigationBar.class)
@ComponentScan("net.elenx")
public class SpringConfig {

    //Create whole view of MainView
    @Bean
    VerticalLayout template(@Qualifier("navigationBar") HorizontalLayout navigationBar) {
        VerticalLayout template = new VerticalLayout();
        //NavigationBar navigationBar = new NavigationBar();
        Sidebar sidebar = new Sidebar();
        template.setMargin(false);
        template.setSpacing(false);
        template.setHeight("100%");
        template.addComponent(navigationBar);
        template.addComponent(sidebar.getSidebar());
        template.setExpandRatio(sidebar.getSidebar(), 1.0f);
        return template;
    }
}

Second config:

@Configuration
@EnableVaadin
public class NavigationBar {

    @Bean
    HorizontalLayout navigationBar(Button hamburgerButton, Label elenxLogo) {
        System.out.println("Hello from NavigationBar bean!");
        HorizontalLayout navbar = new HorizontalLayout();
        navbar.setWidth("100%");
        navbar.setMargin(true);
        navbar.setHeight(50, Sizeable.Unit.PIXELS);
        navbar.addComponent(hamburgerButton);
        navbar.addComponent(elenxLogo);
        navbar.addStyleName("navigation-bar");
        return navbar;
    }

    @Bean
    Button hamburgerButton() {
        Button hamburgerButton = new Button();
        hamburgerButton.addStyleName("hamburger-button");
        hamburgerButton.setIcon(VaadinIcons.MENU);
        return hamburgerButton;
    }

    @Bean
    Label elenxLogo() {
        Label logo = new Label("ElenX");
        logo.addStyleName("elenx-logo");
        logo.setWidthUndefined();
        logo.setEnabled(false);
        return logo;
    }
}

So what's the corrent way of realizing this injection? I want to have Beans for each elements and just inject them to build whole layout. When I tried change this line:

 @Bean
 VerticalLayout template(HorizontalLayout navigationBar) {

To this:

 @Bean
 VerticalLayout template(@Qualifier("navigationBar") HorizontalLayout navigationBar) {

I got "Could not autowire. Qualifier bean must of 'Component' type" error. I'm fresh to Spring and I'm not sure what have I done wrong, shouldn't Spring match my HorizontalLayout navigationBar method with the parameter of VerticalLayout template(HorizontalLayout navigationBar)?


Solution

  • The error message you get tells you that the qualifier bean (this is the HorizontalLayout annotated with @Qualifier("navigationBar")) needs to be a Spring @Component, that is the HorizontalLayout needs to be annotated with @Component which is obviously not possible.

    Another problem that you have with your approach is that Spring beans are by default singletons. So you would end up with exactly one instance of the navigationBar layout in your application. This is of course not enough since you need a new instance for each new UI object created for a user. The navigationBar Spring bean needs to have prototype scope so that a new instance is created by the application context on each injection event.

    This aside, I strongly advise you not to use individual Vaadin UI components for autowiring. The Spring dependency injection mechanism is not meant to be used on this level. You should rather use more coarse-grained components as Spring beans, such as entire Vaadin views or backend services. Building individual UI components (like a navigation bar, forms or views) should be done without dependency injection. Using DI is overkill because you can create instances for common UI components such as a navigation bar, a hamburger button or an elenx logo simply by calling their constructor. There's no need for autowiring inside the UI components which makes the use of the Spring container completely redundant in this case.

    Edit: The best way to modularize Vaadin code on the component level is to use class CustomComponent as base class for new components. You would build a new sub-class of CustomComponent named NavigationBar which you can then instantiate and add to a layout like any other Vaadin component.