Spring Boot: cannot override servletInitialized for CustomSystemMessages

I am using Spring Boot. Inside my UI class, I am defining a servlet class. Everything works fine, except that I cannot override the servlet methods – the servletInitialized() method is never called. What is the correct way to override servletInitialized() with Spring Boot ? It is as if the extension of SpringVaadinServlet was in fact completely irrelevant.

The UI class is defined as follows

@SuppressWarnings("serial") @Theme("owlcms") @Title("owlcms") @SpringUI(path = AppUI.PATH) @Push(value = PushMode.MANUAL, transport = Transport.WEBSOCKET) @Viewport("user-scalable=no,initial-scale=1.0") public class AppUI extends UI implements ViewDisplay, LeaveListener { and inside the AppUI class, there is this definition (I have tried both static and non-static), could not find a good example.

    @VaadinServletConfiguration(ui = AppUI.class, productionMode = true)
    public class AppUIServlet extends SpringVaadinServlet {

        @Override
        protected void servletInitialized() throws ServletException {
            super.servletInitialized();
            System.err.println("AppUIServlet servletInitialized called.");
            VaadinServletService service = getService();
            
            service.setSystemMessagesProvider(new SystemMessagesProvider() {
                @Override
                public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
                    System.err.println("getSystemMessages");
                    CustomizedSystemMessages messages = new CustomizedSystemMessages();
                    // reload automatically, do not display a prompt.
                    messages.setSessionExpiredNotificationEnabled(false);
                    messages.setSessionExpiredURL(null);
                    messages.setSessionExpiredMessage(null);
                    messages.setSessionExpiredCaption(null);
                    return messages;
                }
            });            
        }
    }

Answering myself after reading the source code. Vaadin’s Spring Boot integration creates a SpringVaadinServlet as a managed bean if none has been defined. There is a single servlet, which dispatches to the various URLs registered on the individual SpringUI components.

So the trick is to define a Bean of the VaadinServlet type, before the rest of the initialization takes place. The most convenient place I have found for this is the main Spring Boot application, which incidentally extends SpringBootServletInitializer.

Working example follows.

public class OwlcmsApplication extends SpringBootServletInitializer {
    static {
        SLF4JBridgeHandler.install();
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(OwlcmsApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(OwlcmsApplication.class, args);
    }

    /**
     * Override the default SpringVaadinServlet.
     * Replace servletInitialized so that it registers a customized SystemMessagesProvider
     * 
     * @return an instance of SpringVaadinServlet with custom messages
     */
    @SuppressWarnings("serial")
    @Bean
    public VaadinServlet vaadinServlet() {
        return new SpringVaadinServlet() {

            @Override
            protected void servletInitialized() throws ServletException {
                super.servletInitialized();   
                SystemMessagesProvider systemMessagesProvider = new SystemMessagesProvider() {
                    @Override
                    public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
                        CustomizedSystemMessages messages = new CustomizedSystemMessages();
                        // reload page automatically after restablishing connection to server,
                        // do not display a prompt.
                        messages.setSessionExpiredNotificationEnabled(false);
                        messages.setSessionExpiredURL(null);
                        messages.setSessionExpiredMessage(null);
                        messages.setSessionExpiredCaption(null);
                        return messages;
                        //TODO internationalization of messages
                    };
                };
                getService().setSystemMessagesProvider(systemMessagesProvider);
            }
        };
    }
}