Vaadin With SpringBoot Autowire Failed

HI

I am Using Vaadin 7.6.3 with SpringBoot 1.3.6

I have two classes

  1. SecuredUI extends UI with annotation @SpringUI
  2. MainPanel extends VerticalLayout

Problem is that @Autowired works inside
SecuredUI
but not in [b]
MainPanel

Here are my class details

class 1)
[/b]SpringBootAutowiredApplication.java

package com.vega;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAutowiredApplication {
public static void main(String args) {
SpringApplication.run(SpringBootAutowiredApplication.class, args);
}
}


Class 2) SecuredUI

import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vega.ui.component.MainPanel;
import com.vega.ui.wrapper.ServiceWrapper;

@SpringUI
public class SecuredUI extends UI {

private static final long serialVersionUID = 1L;

@Autowired


public ServiceWrapper mServiceWrapper;

@Override
protected void init(VaadinRequest request) {

    VerticalLayout layout = new VerticalLayout();
    layout.setMargin(true);
    layout.setSpacing(true);
    layout.setSizeFull();

    Button button = new Button("Button");
    button.addClickListener(new ClickListener() {
        private static final long serialVersionUID = 1L;
        @Override
        public void buttonClick(ClickEvent event) {
            eventButtonClickd();
        }
    });

    layout.addComponent(button);
    
    MainPanel mainPanel=new MainPanel(); 
    mainPanel.createControls();
    layout.addComponent(mainPanel);
    setContent(layout);
}

protected void eventButtonClickd() {

    try {
        mServiceWrapper.getSimpleData();   [b]

//Here It is Autowiring
[/b]
} catch (Exception e) {
e.printStackTrace();
}
}
}


Class 3)

MainPanel

package com.vega.ui.component;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.VerticalLayout;
import com.vega.ui.wrapper.ServiceWrapper;

public class MainPanel extends VerticalLayout {

private static final long serialVersionUID = 1L;

@Autowired
private ServiceWrapper mServiceWrapper;

public void createControls() {

    VerticalLayout layout = new VerticalLayout();
    layout.setMargin(true);
    layout.setSpacing(true);

    Button button = new Button("Other Button ");
    button.addClickListener(new ClickListener() {
        private static final long serialVersionUID = 1L;
        @Override
        public void buttonClick(ClickEvent event) {
            eventButtonClickd();
        }
    });

    layout.addComponent(button);
    addComponent(layout);
}


protected void eventButtonClickd() {
    try {
        mServiceWrapper.getSimpleData();  [b]

//Here It is Not Autowiring
[/b]
} catch (Exception e) {
e.printStackTrace();
}
}
}


Class 4) ServiceWrapper

package com.vega.ui.wrapper;
import org.springframework.stereotype.Component;

@Component
public class ServiceWrapper {
public void getSimpleData() {
System.out.println(“Entered ServiceWrapper getSimpleData”);
}
}

Do i need to add any annotation for MainPanel also ?

To make autowire work the instance of MainPanel should be managed by spring too.
Try to annotate your MainPanel with @SpringComponent and @UIScope and the have MainPanel autowired inside your UI

HTH
Marco

Thanks Marco Collovati
I added as follows and initiated MainPanel inside UI with @Autowired

@SpringComponent
@UIScope
public class MainPanel extends VerticalLayout {
}

@Autowired
public MainPanel mMainPanel;

It works fine for me.

What if i use some other child panel inside MainPanel and i want Autowired function inside child also than should i use @SpringComponent ,@UIScope for child class also.

vaadin spring integration mainly focus on UI and View, with uiscope and viewscope, these two scope are specially handled. I suggest you to read source code carefully.

Your code is illed. The prefer way is to use navigator with view. Besides ui and view, all your component should be prototype scoped, Use it totally in spring way. The simple rule is injec applicationcontext in to view, then use applicationContext.getBean() method to got component.

If you follow this rule, you can take all power both from vaadin and spring.

Hi

I have a running Vaadin Project
which uses navigator and Views without SpringBoot it works fine in tomcat 8 and autowiring all will work.
Now i am trying to convert the whole project to run as springboot.
do i need to change my all ui screens add @SpringComponent ,@UIScope .
or is there any way that i can do it.

And if any link or book that show how to use Vaadin with springboot will be helpfull for me.

Regards
Nagaraj RC

“Now i am trying to convert the whole project to run as springboot.
do i need to change my all ui screens add @SpringComponent ,@UIScope .”

Normally yes.

HI

How can i Autowire my MainPanel if it is taking parameters in its constructor like below

public class MainPanel extends VerticalLayout {

public MainPanel(HashMap<String,Object> pDataValues,int pValue) {
mUI = pUI;
mDataValues=pDataValues;
}
}

Thanks
Nagaraj RC

Vaadin is special, It manage UI in server side. Almost all examples you saw initilize component in constructor, But it is not forced.

You can follow a pattern you prefer, that’s solve these problems. for example:

@Component
@Scope("prototype")
public class MainPanel extends VerticalLayout {

  private final ScopeBigThanThisObject sp;
  
  //let injectable injected.
  @Autowired
  public MainPanel(ScopeBigThanThisObject sp) {
    this.sp = sp;
  }
  
  // initialize component later.
  public MainPanel afterInjection(HashMap<String,Object> pDataValues,int pValue) {
    mUI = pUI;
     mDataValues=pDataValues;
     //like some fluent api design.
    return this;
  }
}

Somewhere in your view or ui:

@SpringUI
public class SecuredUI extends UI {

    private static final long serialVersionUID = 1L;

  private final ApplicationContext applicationContext;
  
  //when you got applicationcontext, you got all spring managed.
  @Autowired
  public SecuredUI(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

    @Autowired
    public ServiceWrapper mServiceWrapper;

    @Override
    protected void init(VaadinRequest request) {

        VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        layout.setSpacing(true);
        layout.setSizeFull();

        Button button = new Button("Button");
        button.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;
            @Override
            public void buttonClick(ClickEvent event) {
                eventButtonClickd();
            }
        });

        layout.addComponent(button);
        
        // MainPanel mainPanel=new MainPanel(); 
        MainPanel mainPanel= applicationContenxt.getBean(MainPanel.class).afterInjection(param1, param2...);
        mainPanel.createControls();
        layout.addComponent(mainPanel);
        setContent(layout);
    }

Of cause you can annotate every component to ui scope, But I prefer viewscoped and protype scoped.When you navigate to another view, every component in previous view will be destroyed, when you navigate back, it will be created again.

Hi libo

I followed the approah which you said above with following way


Way 1) :

With no change in SecuredUI and little change in MainPanel. The change is as i not understand purpose of the

private final ScopeBigThanThisObject sp;
which is using inside MainPanel constructor. i just replaced it with UI object as follows

@Autowired
public MainPanel(UI pUI) {
mUI = pUI;
}

and it works.


Way 2) :

And i also tried without using applicationContext.getBean(MainPanel.class); as follows

@Autowired
public MainPanel mMainPanel;

//MainPanel mMainPanel = applicationContext.getBean(MainPanel.class);
mMainPanel.afterInjection(getUI(), new HashMap<String, Object>(), 10);
mMainPanel.createControls();
layout.addComponent(mMainPanel);

with MainPanel annotated using @Component,@Scope(“prototype”) as follows

@Component
@Scope(“prototype”)
public class MainPanel extends VerticalLayout {

}

Which one is the best way i can go with modifying my whole code.

Regards
Nagaraj RC

If you adopt Spring, You should familiar to Spring. ScopeBigThanThisObject means long duration object can inject into short duration objects.
Singleton scoped object can inject into any object, SessionScoped object can inject into requestScoped object, But not at reverse direction.

UIscoped can inject into prototypeScoped object as you had done. It follows rules mentioned above. So it’s fine.

Because you held a reference from UIScoped object to prototypescoped object, the prototypeScoped object will live as long as UI object.

I suggest you spend some times on Spring. I found much questions in this forum is related to basic Spring concept, Not to vaadin self.

One question, Where do you inject mMainPanel? It looks like will cause circular injection.

I inject mMainPanel inside UI as follows

@SpringUI
public class SecuredUI extends UI {

@Autowired
public MainPanel mMainPanel;

@Override
protected void init(VaadinRequest request) {

  //MainPanel mMainPanel = applicationContext.getBean(MainPanel.class);
    mMainPanel.afterInjection(getUI(), new HashMap<String, Object>(), 10);
    mMainPanel.createControls();
    layout.addComponent(mMainPanel);
}

}

But at this case i am not passing UI reference to MainPanel constructor as follows

public MainPanel() {
}

i am passing UI object using below

mMainPanel.afterInjection(getUI(), new HashMap<String, Object>(), 10);

Regards
Nagaraj RC

Perhaps the link below can help someone looking for related documentation
https://vaadin.github.io/spring-tutorial/