Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@UIScope annotation not respected for spring view?

Tags:

spring

vaadin8

I am facing an issue with the Vaadin spring annotation @UIScope, defined as follows:

@SpringComponent
@SpringView(name = AdminView.VIEW_NAME)
@UIScope
public class AdminView extends NavigatingView {
    ...
}

The view is created every time the navigation is opening the view. I would expect that it is created only once, on first time access.

However, if I replace @UIScope with @Scope(UIScopeImpl.VAADIN_UI_SCOPE_NAME) then it works as expected. Did I miss something?

like image 609
Steffen Harbich Avatar asked Mar 08 '23 17:03

Steffen Harbich


1 Answers

It's related to the order of the @SpringView and @UIScope annotations, as the tutorial and the older wiki page briefly suggest:

// Pay attention to the order of annotations

It's probably related to how and when the annotations are processed. I did not dig that deep into the Vaadin code, but as per the the @SpringView javadoc it puts the view into a view-scope by default. Furthermore, I don't think you require the @SpringComponent annotation because you're already using @SpringView to register it a spring component.

Annotation to be placed on View-classes that should be handled by the SpringViewProvider.

This annotation is also a stereotype annotation, so Spring will automatically detect the annotated classes. By default, this annotation also puts the view into the view scope. You can override this by using another scope annotation, such as the UI scope, on your view class. However, the singleton scope will not work!

In the sample below, you'll find 2 views, the first one with the annotations in the correct order, and the second one with them swapped:

@SpringUI
@SpringViewDisplay
public class MyVaadinUI extends UI implements ViewDisplay {

    /* UI */

    private Panel springViewDisplay;

    @Override
    protected void init(VaadinRequest request) {
        VerticalLayout mainLayout = new VerticalLayout();
        HorizontalLayout buttonLayout = new HorizontalLayout();
        springViewDisplay = new Panel();

        buttonLayout.addComponent(new Button("1", event -> getNavigator().navigateTo(FirstView.VIEW_NAME)));
        buttonLayout.addComponent(new Button("2", event -> getNavigator().navigateTo(SecondView.VIEW_NAME)));
        mainLayout.addComponents(buttonLayout, springViewDisplay);
        setContent(mainLayout);

    }

    @Override
    public void showView(View view) {
        springViewDisplay.setContent((Component) view);
    }


    /* VIEWS */

    @UIScope
    @SpringView(name = FirstView.VIEW_NAME)
    public static class FirstView extends HorizontalLayout implements View {

        public static final String VIEW_NAME = "";

        @PostConstruct
        private void init() {
            System.out.println("Created first view");
            addComponent(new Label("First view - " + LocalDateTime.now()));
        }

        @Override
        public void enter(ViewChangeListener.ViewChangeEvent event) {
            // no-op
        }
    }

    @SpringView(name = SecondView.VIEW_NAME)
    @UIScope
    public static class SecondView extends HorizontalLayout implements View {

        public static final String VIEW_NAME = "secondView";

        @PostConstruct
        private void init() {
            System.out.println("Created second view");
            addComponent(new Label("Second view - " + LocalDateTime.now()));
        }

        @Override
        public void enter(ViewChangeListener.ViewChangeEvent event) {
            // no-op
        }
    }
}

As you'll notice in the animation below, when navigating to the second view a new instance is always created, while navigating to the first one will reuse the initial instance:

vaadin-view-uiscope

like image 75
Morfic Avatar answered Mar 20 '23 23:03

Morfic