n00bst3r
n00bst3r

Reputation: 647

Good Practice to realize Dependency Injection with Vaadin and Spring Boot

I have following Problem: I got a Mainview class that extends UI. In this class Dependency Injection works. But this class holds a navigator with views. This view hold Tabsheet that also hold views. Now I need in a view to inject a Spring @Service class. But the DI-Chain is broken. I already know that the Chain of dependency injection shouldn't be interrupted (I found this out through another question here). But I can't find a way to keep this chain alive. Has someone a good tipp how to realize the views beeing also injected and despite of this I can use everywhere the navigator? I think I do it too complicated or even wrong. This is my Mainview (extends UI) Class:

@Theme("valo")
@SpringUI
public class MainView extends UI {

private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(MainView.class);
public static Navigator navigator;
private List<String> availableRealms = new ArrayList<>();
private ComboBox<String> select =new ComboBox<>();

@Autowired
private SpringViewProvider viewProvider;


@Override
protected void init(VaadinRequest request) {
    LOGGER.info("Initializing MainView container...");
    createMainView();

}

public void createMainView(){
    HorizontalLayout comboBoxLayout = new HorizontalLayout();

    comboBoxLayout.addComponent(select);
    availableRealms.add("Master-Realm");
    select.setTextInputAllowed(false);
    select.setItems(availableRealms);
    select.setSelectedItem(availableRealms.get(0));
    LOGGER.info("Building mainView area...");
    final VerticalLayout root = new VerticalLayout();
    root.setSizeFull();
    root.setMargin(true);
    root.setSpacing(true);
    setContent(root);
    final CssLayout navigationBar = new CssLayout();
    //      navigationBar.addComponent(comboBoxLayout);
    navigationBar.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
    navigationBar.addComponent(createNavigationButton("Dashboard",DashBoardView.VIEW_NAME));
    navigationBar.addComponent(createNavigationButton("Realm Settings",RealmSettingsView.VIEW_NAME));
    navigationBar.addComponent(createNavigationButton("Client Management",ClientManagementView.VIEW_NAME));
    navigationBar.addComponent(createNavigationButton("User Management",UserManagementView.VIEW_NAME));
    navigationBar.addComponent(createNavigationButton("Group Management",GroupManagementView.VIEW_NAME));
    comboBoxLayout.addComponent(navigationBar);

    root.addComponent(comboBoxLayout);
    //      root.addComponent(navigationBar);

    final Panel viewContainer = new Panel();
    viewContainer.setSizeFull();
    root.addComponent(viewContainer);
    root.setExpandRatio(viewContainer, 1.0f);
    LOGGER.info("Initializing navigator...");
    navigator = new Navigator(this, viewContainer);
    navigator.addProvider(viewProvider);
    navigator.addView("", DashBoardView.class);

}

/**
 * Creates a new button with listener that uses the navigator.
 * @param caption
 * @param viewName
 * @return <b>Button</b>
 */
private Button createNavigationButton(String caption, final String viewName) {
    Button button = new Button(caption);
    button.addStyleName(ValoTheme.BUTTON_SMALL);
    // If you didn't choose Java 8 when creating the project, convert this to an anonymous listener class
    button.addClickListener(event -> getUI().getNavigator().navigateTo(viewName));
    return button;
}

}

And this is the ClientManagementView that hold a tabsheet:

@SpringView(name = ClientManagementView.VIEW_NAME)
@ViewScope
public class ClientManagementView extends VerticalLayout implements View {

private final Logger LOGGER = LoggerFactory.getLogger(ClientManagementView.class);

private static final long serialVersionUID = 1L;

public static final String VIEW_NAME = "clientmanagementview";

@Autowired
ClientOverview clientOverview;

@Autowired
ClientCreationView clientCreationView;

@Autowired
private TabSheet tabsheet;

@PostConstruct
void init() {
    LOGGER.info("Initializing ClientView...");
    setSizeFull();
    setSpacing(true);
    setMargin(true);
    //      TabSheet tabsheet = new TabSheet();
    tabsheet.addStyleName(ValoTheme.TABSHEET_FRAMED);
    this.addComponent(tabsheet);
    tabsheet.addTab(clientOverview);
    tabsheet.addTab(clientCreationView);
}

@Override
public void enter(ViewChangeEvent event) {
    // do nothing.

}

}

And now the client creation view:

@SpringView(name = ClientCreationView.VIEW_NAME)
@ViewScope
public class ClientCreationView extends VerticalLayout implements View {


private static final long serialVersionUID = 1L;
public static final String VIEW_NAME = "client_creationview";
private final Logger LOGGER = LoggerFactory.getLogger(ClientCreationView .class);

@Autowired
private TabSheet tabsheet;

@Autowired
private ClientCredentialFormular clientCredentialFormular;

@Autowired
private ClientRegisterFormular clientRegisterFormular;

public ClientCreationView(){
    LOGGER.info("Initializing ClientCreationView...");
    this.setCaption("Register New Client");
    LOGGER.info("Initializing ClientView...");
    setSizeFull();
    setSpacing(true);
    setMargin(true);
    //      TabSheet tabsheet = new TabSheet();
    this.addComponent(tabsheet);
    tabsheet.addTab(clientRegisterFormular);
    tabsheet.addTab(clientCredentialFormular);

}

@Override
public void enter(ViewChangeEvent event) {
    // Do nothing...

}

}

And a tab of this view need to inject the service class:

@SpringView(name = ClientRegisterFormular.VIEW_NAME)
@ViewScope
public class ClientRegisterFormular extends VerticalLayout implements View {

private static final long serialVersionUID = 1L;
public static final String VIEW_NAME = "client_data_formular";
private static final Logger LOGGER = LoggerFactory.getLogger(ClientRegisterFormular.class);

@Autowired
IClientService clientService;

private TextField clientIdField = new TextField("Client-Id");
private TextField rootUriField = new TextField("Root-URI");
private TextField redirectUriField = new TextField("Redirect-URI");
private Button saveButton = new Button("Save");
private Button cancelButton = new Button("Cancel");
private FormLayout form = new FormLayout();
private SaveButtonListener saveButtonListener = new SaveButtonListener(this);
private CancelButtonListener cancelButtonListener = new CancelButtonListener(this);


public ClientRegisterFormular(){
    LOGGER.info("Initializing Client Data Formular...");
    this.setCaption("Client Data");
    this.setSizeFull();
    this.setSpacing(true);
    this.setMargin(true);
    /*
     * Panel for Formular:
     */
    Panel panel = new Panel("Register Client");
    panel.addStyleName("regFormPanel");
    panel.setSizeUndefined(); // Shrink to fit content

    //Formular:
    this.form.setMargin(true);
    this.form.setSizeFull();
    this.clientIdField.setWidth("900px");
    this.clientIdField.setRequiredIndicatorVisible(true);
    form.addComponent(clientIdField);
    this.rootUriField.setRequiredIndicatorVisible(true);
    this.rootUriField.setWidth("900px");
    form.addComponent(rootUriField);
    this.redirectUriField.setRequiredIndicatorVisible(true);
    this.redirectUriField.setWidth("900px");
    form.addComponent(redirectUriField);
    //TODO Checkboxes for

    //Button-Layout:
    HorizontalLayout buttonLayout = new HorizontalLayout();
    this.saveButton.addClickListener(saveButtonListener);
    buttonLayout.addComponent(this.saveButton);
    this.cancelButton.addClickListener(this.cancelButtonListener);
    buttonLayout.addComponent(this.cancelButton);
    buttonLayout.setComponentAlignment(this.saveButton, Alignment.TOP_LEFT);

    form.addComponent(buttonLayout);
    panel.setContent(form);
    this.addComponent(panel);
    //      this.addComponent(buttonPanel);
    this.setComponentAlignment(panel, Alignment.TOP_LEFT);

}

@Override
public void enter(ViewChangeEvent event) {
    // Do nothing..

}


private static class SaveButtonListener implements Button.ClickListener{

    private static final long serialVersionUID = 1L;
    private ClientRegisterFormular clientRegisterFormular;

    public SaveButtonListener(ClientRegisterFormular clientRegisterFormular){
        this.clientRegisterFormular = clientRegisterFormular;
    }

    @Override
    public void buttonClick(ClickEvent event) {
        LOGGER.info("Saving client...");
        Client newClient = new Client();
        newClient.setClientId(clientRegisterFormular.clientIdField.getValue());
        newClient.setRootUri(this.clientRegisterFormular.rootUriField.getValue());
        newClient.setRedirectUri(this.clientRegisterFormular.redirectUriField.getValue());
        newClient.setClientId(UUID.randomUUID().toString());
        this.clientRegisterFormular.clientService.createClient(newClient);
        refreshView();

    }

    public void refreshView() {
        MainView.navigator.navigateTo(ClientManagementView.VIEW_NAME);
    }

}

private static class CancelButtonListener implements Button.ClickListener{

    private static final long serialVersionUID = 1L;
    private ClientRegisterFormular clientRegisterFormular;

    public CancelButtonListener(ClientRegisterFormular clientRegisterFormular){
        this.clientRegisterFormular = clientRegisterFormular;
    }

    @Override
    public void buttonClick(ClickEvent event) {
        LOGGER.info("Canceling Client Creation...");
        refreshView();

    }


    public void refreshView() {
        MainView.navigator.navigateTo(ClientManagementView.VIEW_NAME);
    }

}

}

Upvotes: 0

Views: 593

Answers (2)

n00bst3r
n00bst3r

Reputation: 647

I resolved it. The problem wasn't that the tabsheet isn't a spring component(cause I declared it wiht @bean in the application class). The problem was that I didn't it autowire by constructor. By setting the tabsheet as a parameter of the contructor and set the autowire there I resolved it.

Upvotes: 1

Alejandro Casagrande
Alejandro Casagrande

Reputation: 56

I think that the problem is in ClientManagementView, where you are creating both views:

tabsheet.addTab(new ClientOverview());
tabsheet.addTab(new ClientCreationView());

But it should be spring the that should create those views, as you declared them as @SpringView and you want to be injected the others beans.

I think that you should autowire them in ClientManagementView:

@Autowired
ClientOverview clientOverview;

@Autowired
ClientCreationView clientCreationView;


tabsheet.addTab(clientOverview);
tabsheet.addTab(clientCreationView);

Upvotes: 0

Related Questions