Search code examples
vaadinvaadin-flowvaadin14

How can I reroute in BeforeEnterObserver in the view before AppLayout is rendered in Vaadin 14 (Vaadin Flow)


So for example let's I have:

public class MainView extends AppLayout {
   public MainView() {
      User user = VaadinSession.getAttribute("user");
      if(user.isCheckSomething())
          Span span = new Span("Hello " + user.getFirstname());
   }
}

This will fail with a NPE if the user is not already logged in as getting the User from the session will be null. Now I could add a null check before the if(user.isCheckSomething()) but ideally I would prefer not to have the AppLayout rendered at all if the user is not logged in. That is I'd rather fail in the view through BeforeEnterObserver in the public void beforeEnter(BeforeEnterEvent event) method however the AppLayout is called and created before the beforeEnter(...) method is called.

In other words how can I force the instantiation of AppLayout to be skipped entirely if the user isn't logged in through the view so that the AppLayout is never constructed.


Solution

  • As a rule of thumb, it's really not reliable to work with the UI in the constructor in any way, since it's not initialized yet.

    AppLayout has its own afterNavigation method which should be called after BeforeEnterEvent.

    public class MainView extends AppLayout {
        @Override
        protected void afterNavigation() {
            super.afterNavigation();
            User user = VaadinSession.getAttribute("user");
            if(user.isCheckSomething())
                Span span = new Span("Hello " + user.getFirstname());
        }
    

    So in beforeEnter method you will reroute to login, otherwise the after navigation from the parent layout will be fired.

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (!isAuthenticated()) {
            event.rerouteTo(LoginView.class);
        }
    }
    

    You can either implement BeforeEnterObserver in each of your views and check if user is authenticated over and over again... or you can do it once:

    @SpringComponent
    public class AuthenticationControl implements VaadinServiceInitListener {
         @Override
        public void serviceInit(ServiceInitEvent event) {
            event.getSource().addUIInitListener(uiEvent -> {
                final UI ui = uiEvent.getUI();
                ui.addBeforeEnterListener(/* do the check here, either with a method reference or create a separate listener class */);
            });
         }
    }