Advanced Topics
|
This section documents the current Vaadin release line — Vaadin 24 LTS / 25.x, Java 17+, Spring Boot 3 / Jakarta EE 10 — as published at the official Vaadin documentation, which is the reference these pages are written and verified against. No specific patch version is pinned. Flow (server-side Java) is the authoring style used throughout, with Hilla / React shown where it differs; Vaadin 7 and the pre-Flow architecture appear only as migration contrast. This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since Vaadin ships major releases roughly twice a year and its ecosystem iterates. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page collects the Flow features an application reaches for once the basics are in place. Each is small on its own; together they cover lifecycle, error handling, refresh behaviour, file transfer and internationalisation. It follows the Advanced Topics section.
Lifecycle hooks
A VaadinServiceInitListener runs once at startup and is the place to register the other listeners.
Discovered automatically as a Java service or a Spring bean:
@Component
public class ApplicationInitListener implements VaadinServiceInitListener {
@Override
public void serviceInit(ServiceInitEvent event) {
event.getSource().addUIInitListener(uiEvent -> {
UI ui = uiEvent.getUI();
ui.addBeforeEnterListener(this::checkMaintenanceMode);
});
event.getSource().addSessionInitListener(sessionEvent ->
sessionEvent.getSession().setErrorHandler(new AppErrorHandler()));
}
}
IndexHtmlRequestListener (and, in bootstrap mode, BootstrapListener) let you modify the served HTML shell.
Error handling and system messages
A session ErrorHandler catches exceptions thrown from UI event handlers that nothing else handled:
public class AppErrorHandler implements ErrorHandler {
@Override
public void error(ErrorEvent event) {
LoggerFactory.getLogger(getClass()).error("Unhandled", event.getThrowable());
UI.getCurrent().access(() ->
Notification.show("Something went wrong.").addThemeVariants(
NotificationVariant.LUMO_ERROR));
}
}
The messages Vaadin shows for session expiry, an internal error, or a lost connection are overridden with a
SystemMessagesProvider:
service.setSystemMessagesProvider(info -> {
CustomizedSystemMessages messages = new CustomizedSystemMessages();
messages.setSessionExpiredCaption("Session ended");
messages.setSessionExpiredMessage("Please sign in again.");
messages.setSessionExpiredNotificationEnabled(true);
return messages;
});
Preserving a view across refresh
By default a browser refresh builds a fresh UI and view instance. @PreserveOnRefresh on a view (or its
layout) keeps the same instance — and its unsaved state — when the user reloads the same URL:
@Route("wizard")
@PreserveOnRefresh
public class WizardView extends VerticalLayout { }
Loading indicator
The blue progress bar Vaadin shows during a slow server round trip is themable and its delays are configurable:
ui.getLoadingIndicatorConfiguration().setFirstDelay(300);
ui.getLoadingIndicatorConfiguration().setSecondDelay(1500);
ui.getLoadingIndicatorConfiguration().setThirdDelay(5000);
Downloads and uploads
Stream a generated file through a StreamResource behind an Anchor; receive an uploaded file with the
Upload component and a Receiver:
StreamResource report = new StreamResource("report.pdf",
() -> new ByteArrayInputStream(reportService.pdf()));
Anchor download = new Anchor(report, "Download report");
download.getElement().setAttribute("download", true);
Upload upload = new Upload(new MemoryBuffer());
upload.addSucceededListener(e -> importService.process(
((MemoryBuffer) upload.getReceiver()).getInputStream()));
Long-running tasks
Use the managed VaadinExecutor (Server Push) so background work carries the Vaadin
and security context and is cancelled on UI detach:
executor.execute(ui, () -> {
Result r = slowJob.run();
ui.access(() -> render(r));
});
Internationalisation
Implement I18NProvider (a Spring bean or Java service), back it with ResourceBundle files, and call
getTranslation(key, args…) from views:
@Component
public class MessagesProvider implements I18NProvider {
private static final List<Locale> LOCALES = List.of(Locale.ENGLISH, new Locale("es"));
@Override public List<Locale> getProvidedLocales() { return LOCALES; }
@Override
public String getTranslation(String key, Locale locale, Object... params) {
String pattern = ResourceBundle.getBundle("messages", locale).getString(key);
return MessageFormat.format(pattern, params);
}
}
// in a view
add(new Span(getTranslation("customer.greeting", customer.getName())));
# messages_es.properties
customer.greeting = Hola, {0}
Set a right-to-left locale’s direction on the UI:
UI.getCurrent().setDirection(Direction.RIGHT_TO_LEFT);
See Localization.
See also
-
Server Push —
VaadinExecutor,UI.accessand background work. -
Routing and Navigation —
@PreserveOnRefreshand navigation listeners. -
Configuration and Dev Tools — the
vaadin.*properties these APIs complement. -
Security — session and error handling around authentication.
-
Advanced Topics — the official section.