Why autowired does not work

Hi guys, I am using Vaadin 8 and vaadin spring

I don’t know why autowired, in some classes doesn’t work.

For example, I have my UI:

[code]
@Theme(“gcc”)
@SpringUI
@SpringViewDisplay
public class Application extends UI implements ViewDisplay {

/**
 *
 */
private static final long serialVersionUID = 1L;

@Autowired
private SpringNavigator navigator;

@Autowired
private AccountService accountService;

private Panel springViewDisplay;

private String oldViewName;

private String currentViewName;

private List<String> list;

@Override
protected void init(VaadinRequest request) {

    navigator.init(this, (ViewDisplay) this);
}

@Override
public void showView(View view) {

    MHorizontalLayout hl = new MHorizontalLayout();
    hl.withResponsive(true).withSpacing(false).withFullHeight().withFullWidth();

    springViewDisplay = new Panel();
    springViewDisplay.setSizeFull();

    hl.addComponent(springViewDisplay);
    hl.setExpandRatio(springViewDisplay, 1.0f);

    setContent(hl);

    springViewDisplay.setContent((Component) view);
}

@WebListener
public static class MyContextLoaderListener extends ContextLoaderListener {
}

@Configuration
@EnableVaadin
public static class MyConfiguration {

    @Bean
    @UIScope
    public SpringNavigator navigator() {
        return new SpringNavigator();
    }

}

@WebServlet(urlPatterns = { "/ui/*", "/VAADIN/*" }, name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = Application.class, productionMode = false)
public static class MyUIServlet extends SpringVaadinServlet {
}

}
[/code]Here autowired works fine.

Then I have, for example, a view:

@ViewScope
@SpringView(name = SupplierDetail.VIEW_NAME)
public class SupplierDetail extends VerticalLayout implements View {
    public static final String VIEW_NAME = "supplier/detail";

    @Autowired
    private MessageNotificationService notificationService;

    @Autowired
    private FileReferenceService fileReferenceService;

    @Autowired
    private SupplierService supplierService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private DocumentService documentService;

    @Autowired
    private CompanyService companyService;

    @PostConstruct
    void init() {

       ......
       
       Button reject = new Button(I18NHelper.i18n("ui.view.supplier.rejectLabel"), new ClickListener() {
                    private static final long serialVersionUID = 1989848854345501210L;

                    @Override
                    public void buttonClick(ClickEvent event) {

                        Window win = new RejectSupplierWindow(supplier);
                        win.setModal(true);
                        win.setWidth("500px");
                        win.setHeight("300px");
                        win.setResizable(false);
                        UI.getCurrent().addWindow(win);

                    }
                });
    }

    @Override
    public void enter(ViewChangeEvent event) {
        // This view is constructed in the init() method()
    }

}

Also here, autowired works fine.

If you look at view, you noticed a button reject which open a window.
The window code is:

public class RejectSupplierWindow extends Window{

    @Autowired
    private SupplierService supplierService;

    @Autowired
    private MessageNotificationService notificationService;

    public RejectSupplierWindow(Supplier supplier) {
        setContent(buildLayout());
    }

    public ComponentContainer buildLayout() {

        VerticalLayout layout = new VerticalLayout();
        Label label = new Label("E' necessario aggiungere delle note al rifiuto");

        notes.setRows(5);
        notes.setWidth("300px");
        layout.addComponents(label, notes, buildActions());

        return layout;
    }

    public HorizontalLayout buildActions() {

        HorizontalLayout hl = new HorizontalLayout();
        hl.setHeight("30px");

        // pulsante per edit
        Button save = new Button("Save");
        save.addStyleName(ValoTheme.BUTTON_SMALL);
        save.addClickListener(e -> rejectSupplier());

        // pulsante per view details
        Button cancel = new Button("Cancel");
        cancel.addStyleName(ValoTheme.BUTTON_SMALL);
        cancel.addClickListener(e -> this.close());

        hl.addComponents(save, cancel);

        return hl;

    }

    private void rejectSupplier(Supplier s) {

        ....
       // if here I do
       supplierService.MY_FUNCTION;
      // I got the null pointer on supplierService, it seems that the autowired doesn't work
    }

}

As you can see in the code window, if I call MY_FUNCTION of supplierService, I got an error…
Maybe I missed some annotations on the class window?
Please help me

I think is my fault, because I do new Window() …
So in this case, I have to autowired class Window?

I don’t know how to proceed, without do new Window(), in order to show the window

Hi,
you’re right, the object must be managed by spring in order to have autowiring working.

You can try either to:

  1. define a constructor for RejectSupplierWindow that takes all dependencies and inject those in the view; in the button listener you can invoke new RejectSupplierWindow(....)
  2. define the RejectSupplierWindow as a prototype scoped bean and inject a ObjectProvider<RejectSupplierWindow> in the view class; in this case in the button listener you can call provider.getObject(supplier) and spring will autowire all your dependencies

HTH
Marco

One thing to consider, do you even need a fresh Window instance every time the button is clicked, or can you reuse one RejectSupplierWindow and update it with new data? If you can reuse it, just autowire an instance (use @SpringComponent and for example @ViewScoped on RejectSupplierWindow) and show it when the button is clicked.

Thank you guys!

I followed your suggested, and all is good!