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