Search code examples
guicevaadinguice-servlet

Vaadin Window component not fully injected with Guice


I have a very simple Vaadin application. I want to inject the main window of my Vaadin app using Guice.

My problem is that my main window is injected, but none of my @Inject directives inside this main window component are processed.

The full code source of my use cas is available on a bitbucket repo

The Vaadin application class:

public class MyVaadinApplication extends Application {

    protected final Provider<MainWindow> mainWindowProvider;

    @Inject
    @Named("title")
    protected String title;

    @Inject
    public MyVaadinApplication(Provider<MainWindow> mainWindowProvider) {
        this.mainWindowProvider = mainWindowProvider;
    }

    @Override
    public void init() {
        System.out.println("MyVaadinApplication:: found value <"+title+"> for injected title");
        setMainWindow(this.mainWindowProvider.get());
    }
}

The MainWindow class:

public class MainWindow extends Window {

    @Inject
    @Named("title")
    protected String title;
    @Inject
    @Named("label")
    protected String label;
    private static int globalCounter = 0;
    private int localCounter;

    public MainWindow(String caption, ComponentContainer content) {
        super(caption, content);
        initUI();
    }

    public MainWindow(String caption) {
        super(caption);
        initUI();
    }

    public MainWindow() {
        super();
        initUI();
    }

    private void initUI() {
        localCounter = globalCounter;
        globalCounter++;
        this.setCaption(title);
        this.addComponent(new Button(label+" ("+localCounter+")"));
    }
}

The GuiceServletContextListener where the guice binding are defined:

public class GuicyServletConfig extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {

        ServletModule module = new ServletModule() {

            @Override
            protected void configureServlets() {
                serve("/*").with(GuiceApplicationServlet.class);

                bind(Application.class).to(MyVaadinApplication.class).in(ServletScopes.SESSION);
                bind(MainWindow.class).in(ServletScopes.SESSION);
                bindConstant().annotatedWith(Names.named("title")).to("This is a guicy Vaadin Application");
                bindConstant().annotatedWith(Names.named("label")).to("Guice me!");
            }
        };

        Injector injector = Guice.createInjector(module);

        return injector;
    }
}

What happens is that the MainWindow is correctly injected, but the label and title strings are always null. Any idea?


Solution

  • the solution is to inject anything that need to be injected in the MainWindow class using constructor instead of field injection. See the tag stackoverflow-working-with-constructor-injection on the hg repo.

    Samples of the source code

    public class MainWindow extends Window {
    
        protected String title;
        protected String label;
        protected LabelCaption labelCaption;
        private static int globalCounter = 0;
        private int localCounter;
    
        @Inject
        public MainWindow(@Named("title") String title, @Named("label") String label, LabelCaption labelCaption) {
            super();
            this.title = title;
            this.label = label;
            this.labelCaption = labelCaption;
            initUI();
        }
    
        private void initUI() {
            localCounter = globalCounter;
            globalCounter++;
            this.setCaption(title);
            String labelFromLabelCaption = "labelCaption is null";
            if (labelCaption != null) {
                labelFromLabelCaption = labelCaption.getCaption();
            }
            this.addComponent(new Button(label + "/" + labelFromLabelCaption + "/(" + localCounter + ")"));
        }
    }
    

    Does not know yet why field injection does not work in this case.

    The solution was injected to me thanks to this post.