Upgrading Guide
Instructions for upgrading to the latest Vaadin version. To run applications or components developed with Vaadin 7 or 8 inside an application written using the latest version, see Multiplatform Runtime.
Before You Start
-
Delete the
node_modules
folder and either lock file:package-lock.json
(with npm) orpnpm-lock.yaml
(with pnpm) -
Edit the
pom.xml
file and change the Vaadin version tonew version
.
-
Update Spring Version.
Vaadin is compatible with Spring 5.3.0 or newer, and Spring Boot 2.4.0 or newer. If your application uses an older version of Spring, update it to a compatible version:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
</parent>
Upgrade Steps | 14 → 15
Update Main Layout/View Annotations
Several annotations typically placed on the MainLayout
/ MainView
class must be moved to a class that implements the AppShellConfigurator
interface, for example:
@PWA(name = "My Vaadin App", shortName = "my-app")
public class AppShell implements AppShellConfigurator {
}
see set of annotations to modify the Bootstrap page for more details.
Replace obsolete APIs
A set of API breaking changes and their replacements are listed below:
-
Property synchronization methods in
Element
are replaced with similar API inDomListenerRegistration
:getSynchronizedPropertyEvents
,getSynchronizedProperties
,removeSynchronizedPropertyEvent
,removeSynchronizedProperty
,addSynchronizedPropertyEvent
,addSynchronizedProperty
,synchronizeProperty
. -
JavaScript execution APIs
executeJavaScript
andcallFunction
inElement
andPage
are replaced with similarly named methods that give access to the return valueexecuteJs
andcallJsFunction
: -
Miscellaneous
Element
methods:Element(String, boolean)
,addEventListener(String, DomEventListener, String…)
-
Device and platform detection methods
WebBrowser#isIOS()
,WebBrowser#isIPad()
,BrowserDetails#isSafariOrIOS()
,BrowserDetails#isIOS()
,BrowserDetails#isIPad()
are replaced with method inExtendedClientDetails
:isIPad()
,isIOS()
-
Methods
JsModule#loadMode()
andPage#addJsModule(String, LoadMode)
for setting the load mode of JsModule are removed since it does not function with JavaScript modules. -
The construction methods
BeforeEvent(NavigationEvent, Class<?>)
andBeforeEvent(Router, NavigationTrigger, Location, Class<?>, UI)
inBeforeEvent
are replaced withBeforeEvent(NavigationEvent, Class, List)
andBeforeEvent(Router, NavigationTrigger, Location, Class, UI, List)
-
Methods
getUrl()
,getUrlBase()
andgetRoutes()
inRouter
are replaced with methodsgetUrl()
,getUrlBase()
andgetAvailableRoutes()
inRouterConfiguration
. Theresolve()
method inRouter
is replaced with theresolve()
method inRouteUtil
. ThegetRoutesByParent()
method inRouter
is removed and has no replacement. -
ServletHelper
is replaced withHandlerHelper
-
ExecutionCanceler
is replaced withPendingJavaScriptResult
-
The
getBodyAttributes
method inAbstractTheme
,Lumo
andMaterial
is replaced withgetHtmlAttributes
-
The
removeDataGenerator
method inHasDataGenerators
andCompositeDataGenerator
is removed in favor of using the registration returned fromaddDataGenerator(DataGenerator)
-
The methods
preventsDefault
andstopsPropagation
inShortcutRegistration
are replaced withisBrowserDefaultAllowed ` and `isEventPropagationAllowed
-
The
safeEscapeForHtml
method inVaadinServlet
is removed in favor of usingorg.jsoup.nodes.Entities#escape(String)
-
The static method
getInstance
inApplicationRouteRegistry
is removed in favor of the instance method. -
The protected instance method
getApplicationUrl
fromVaadinServlet
is removed
Bootstrapping Changes
For applications upgraded from earlier versions of Vaadin, client-side bootstrapping requires replacing the usages of the V10-14 BootstrapHandler
APIs with their IndexHtmlRequestHandler
API counterparts as described in IndexHtmlRequestListener interface section.
The reason for this API change is that with client-side bootstrapping the initial page HTML generation is separated from loading the Flow client and creating a server-side UI
instance.
-
In Vaadin 10 to 14 these two steps are combined and the
index.html
page includes the code and configuration needed to start the Flow client engine and link the browser page to the server-sideUI
instance. -
In Vaadin 15+ with client-side bootstrapping the
index.html
page includes only the basic HTML markup and links to the TypeScript UI code. When adding routes in TypeScript, theUI
is not guaranteed to be created, thus is optional. It will be only available after the user navigates to a server-side route.
It is also possible to continue using the bootstrapping mode in V10-14 with the useDeprecatedV14Bootstrapping
flag.
See how the use the flag in Configuration Properties.
-
Vaadin Fusion doesn’t involve any API breaking changes between versions 14 and 15. See the release notes at https://github.com/vaadin/platform/releases/tag/15.0.0.
Upgrade Steps | 15 → 16
Vaadin 16 doesn’t involve any API breaking changes. See the release notes at https://github.com/vaadin/platform/releases/tag/16.0.0.
Upgrade Steps | 16 → 17
Move annotations to AppShellConfigurator
The only place where configuring the app with certain annotations is supported is in a class that implements AppShellConfigurator
.
This applies for v15+ bootstrap mode (the default), but not for v14 legacy bootstrapping.
Rather than showing nondeterministic behavior and logging an error, the build will fail when any of the following annotations occur outside an AppShellConfigurator
class:
Meta.class, PWA.class, Inline.class, Viewport.class, BodySize.class, Push.class
Replace obsolete APIs
A new API for Binding Items to Components:
-
HasDataProvider
andHasItems
are now replaced by newHasListDataView
,HasLazyDataView
andHasDataView
interfaces inGrid
,Select
andCheckBoxGroup
. It will be also gradually replaced in other components which have an items binding. -
setDataProvider()
is now deprecated and it is recommended to use overloadedsetItems()
methods. -
setItems
methods now have a return type instead of void. -
HasItemsAndComponents
interface has been replaced byHasItemComponents
in order to support the Data View API in in-memory binding components. -
HasHierarchicalDataProvider
no longer hassetItems
overloads forCollection
,Stream
andArray
.
URL parameters template feature:
-
BeforeEvent
has a bunch of new methods for forwarding, rerouting and getting the parameters. Some methods are now deprecated or removed. -
RouteRegistry
,SessionRouteRegistry
interfaces are now supplemented with new methods and deprecate getters for route layouts. -
com.vaadin.flow.server.startup.RouteTarget
has been completely removed. This class was internal and should not have been used. If you have been using it, please create an issue describing what you needed it for.
Upgrade Steps | 17 → 18
-
Using
LitTemplate
is recommended over deprecatedPolymerTemplate
for doing layouts with HTML and UI logic in Java. It is recommended to use TypeScript for the template and this has been updated to the examples in the documentation. -
Starting from Vaadin 18, the initial attribute values in the template are reflected to the server side state when
@Id
mapping components. This applies toPolymerTemplate
too. More information on the template support is available in this blog post.
Flow Breaking Changes
-
AppShellRegistry
methodgetTitle()
is removed It was broken and could not work. Instead, if needed, usegetUI().getUIInternals().getAppShellTitle()
. -
Having the
@Theme
annotation on Flow views or router layouts will no longer be allowed. The annotation should be onAppShellConfigurator
instead. This is now consistent with the@PWA
annotation. It is also cleaner, since you can only have one@Theme
per application. -
AbstractListDataView
now requires an extra constructor argument - a callback, which is invoked each time when the component’s filter and/or sorting changes through the data view API.
Fusion Breaking Changes
-
The
value
property ofBinderNode
now has optionallyundefined
type for non-initialized optional fields.
Upgrade Steps | 18 → 19
-
Vaadin Flow doesn’t involve any API breaking changes between versions 18 and 19. See the release notes at https://github.com/vaadin/platform/releases/tag/19.0.0.
Fusion Breaking Changes
Generated @Id Field Is Now of Optional Type in TypeScript
A field with @Id
annotation in Java is now of optional type in the generated TypeScript code.
Given an entity with an id
field:
public class Entity {
@Id
private int id;
}
Now in the TypeScript files, instead of using endpoint.getEntity(entity.id)
, you might need to change to endpoint.getEntity(entity.id!)
(if you know that the id
is always set when this is called) or add a type guard to explicitly check that id
is not undefined
.
Ignore One More Service Worker Related Static File
You need to ignore one more static file, /sw-runtime-resources-precache.js
, if you use HttpSecurity.authorizeRequests()
to do role-based authorization in your security configuration as follows:
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http.authorizeRequests().anyRequest().hasAnyAuthority(Role.getAllRoles());
...
}
In this situation, you need to add one more file /sw-runtime-resources-precache.js
to the static resource list that Spring Security bypasses:
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(
// client-side JS code
"/VAADIN/**",
...
// web application manifest
"/manifest.webmanifest",
"/sw.js",
"/offline-page.html",
"/sw-runtime-resources-precache.js",
...
);
}
Ignore the Service Worker Initiated Requests
Another potential Spring Security related breaking change is about using HttpSecurity.requestCache()
to redirect the user to the intended page after login.
An example of using HttpSecurity.requestCache()
:
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http
// Register our CustomRequestCache, that saves unauthorized access attempts, so
// the user is redirected after login.
.requestCache().requestCache(new CustomRequestCache())
// Restrict access to our application.
.and().authorizeRequests()
// Allow all flow internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
...
}
Now you need to ignore the service worker initiated requests, otherwise the access attempts are overridden by the service worker requests and Spring cannot redirect you to the intended page.
This can be done by inspecting the Referer
header of the request.
The SecurityUtils::isFrameworkInternalRequest()
can be updated as follows to also include the service worker initiated requests:
static boolean isFrameworkInternalRequest(HttpServletRequest request) {
final String parameterValue = request
.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER);
// Use Referer in header to check if it is a service worker
// initiated request
String referer = request.getHeader("Referer");
boolean isServiceWorkInitiated = (referer != null
&& referer.endsWith("sw.js"));
return isServiceWorkInitiated
|| parameterValue != null
&& Stream.of(RequestType.values())
.anyMatch(r -> r.getIdentifier().equals(parameterValue));
}
Upgrade Steps | 19 → 20
-
Vaadin Flow doesn’t involve any API breaking changes between versions 19 and 20. See the release notes at https://github.com/vaadin/platform/releases/tag/20.0.0.
Fusion Breaking Changes
Endpoints Access is Denied by Default
Previously, endpoints (methods in classes with @Endpoint
annotation) without security annotations (one of @DenyAll
, @PermitAll
, @RolesAllowed
, @AnonymousAllowed
) were accessible by all authenticated users.
To avoid inadvertent exposure of methods as endpoints, @DenyAll
is now the default.
This means that you need to add explicit security annotations to the endpoints that you want to make accessible (either at the class level or the method level).
Default Spring Security Configuration
A default class for Spring Security configuration is available as VaadinWebSecurityConfigurerAdapter
. Extend this class instead of the default WebSecurityConfigurerAdapter
to automatically get a configuration that allows Vaadin specific requests to pass through security while requiring authorization for all other requests:
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
// app's own HttpSecurity configuration as needed ...
}
@Override
protected void configure(WebSecurity web) throws Exception {
super.configure(web);
// app's own WebSecurity configuration as needed...
}
}
VaadinWebSecurityConfigurerAdapter
configures authentication for all routes by default.
Modify this behavior with your own followup configuration as needed.
It also bypasses framework internal and static resources (/VAADIN/**
, sw.js
…).
Previously, these had to be explicitly matched and ignored in the app.
VaadinWebSecurityConfigurerAdapter
also configures Spring CSRF token for login and Fusion endpoint requests, so you no longer need to ignore Spring CSRF protection for them like before with http.csrf().ignoringAntMatchers("/login", "/connect/**");
The client-side login()
method now needs the Spring CSRF token returned from a login success handler VaadinSavedRequestAwareAuthenticationSuccessHandler
.
You can update your login view configuration with the setLoginView()
helper, which sets up the login success handler automatically.
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
setLoginView(http, "/login");
}
Upgrade Steps | 20 → 21
Lit Templates Use Lit 2
Previously, Lit templates were based on LitElement 2.x and lit-html 1.x. New Lit 2.0 (which includes LitElement 3.x and lit-html 2.x) is used for Lit templates in the latest Vaadin version. Some changes are required to be able to use your existing template with Lit 2.0. Please refer to the Lit Upgrade Guide to find all the necessary changes. Most of the necessary changes are with imports.
Use the lit
package.
For example, change imports of html
and LitElement
from:
import { html, LitElement } from 'lit-element';
to:
import { html, LitElement } from 'lit';
Update decorator imports.
Decorators have been moved to a separate module.
For example, change customElement
and property
decorator imports from:
import { customElement, property } from 'lit-element';
to:
import { customElement, property } from 'lit/decorators.js';
Update directive imports from:
import { repeat } from 'lit-html/directives/repeat.js';
to:
import { repeat } from 'lit/directives/repeat.js';
Some Lit APIs have been renamed.
The most noticeable change is that the @internalProperty
decorator has been renamed to @state
.
The Vaadin Web Components No Longer Support <template>
The Vaadin Web Components no longer support <template>
to render content.
Please, use renderer functions instead.
Alternatively, you can use the @vaadin/vaadin-template-renderer
package which is created to maintain backward compatibility.
Installation
Install vaadin-template-renderer
as follows:
npm i @vaadin/vaadin-template-renderer --save
Import vaadin-template-renderer
before any other components:
import '@vaadin/vaadin-template-renderer';
Deprecation Warning
By default, vaadin-template-renderer
shows a deprecation warning when <template>
is used with a component.
To suppress the warning, add the suppress-template-warning
attribute to the component:
<vaadin-combo-box suppress-template-warning>
<template>
Content
</template>
</vaadin-combo-box>
-
Vaadin Flow doesn’t involve any API breaking changes between versions 20 and 21. See the release notes at https://github.com/vaadin/platform/releases/tag/21.0.0.
Fusion Breaking Changes
Fusion Package Renaming
In order to give Fusion a better identity, we renamed the following Fusion packages:
-
com.vaadin.flow.server.connect
tocom.vaadin.fusion
-
com.vaadin.flow.server.frontend.fusion
tocom.vaadin.fusion.frontend
-
com.vaadin.flow.server.startup.fusion
tocom.vaadin.fusion.startup
TypeScript Code Generation Nullability Change
Previously, all the Java types are generated as required in TypeScript.
Now it changes so that for any type that is nullable in Java, it is optional in TypeScript, that is, the value could be undefined
. See the GitHub issue.
To upgrade, you can either: Update the client-side code to handle undefinable value.
// The address property is never undefined in Vaadin 20
person.address.street
// Use the question mark to deal with undefinable properties in Vaadin 21
person.address?.street
// The list returned from the endpoint is never undefined in Vaadin 20
const items = await endpoint.list();
// Use the double question mark to give a default value in Vaadin 21
const item = (await endpoint.list()) ?? [];
Or use @Nonnull
annotation on the server-side to keep the same code generation behavior as before.
public class Person {
@Nonnull
private Address address;
}
Tip
|
@Nonnull annotation@Nonnull annotations available or even your own one.
Vaadin uses case-insensitive string comparison for checking the annotation.
|
See Type Nullability for more details.
Upgrade Steps | 21 → 22
See the Design System Upgrading Guide for component specific instructions.
-
Vaadin Flow doesn’t involve any API breaking changes between versions 21 and 22. See the release notes at https://github.com/vaadin/platform/releases/tag/22.0.0.
Fusion Breaking Changes
Frontend npm Package
Fusion frontend code was moved from @vaadin/flow-frontend
to @vaadin/fusion-frontend
.
Fusion module imports need to be updated correspondingly.
For example, importing Fusion EndpointError
needs to be changed as follows, from:
import { EndpointError } from '@vaadin/flow-frontend';
to:
import { EndpointError } from '@vaadin/fusion-frontend';
TypeScript 4.4 Default Catch Variable Type
Vaadin has changed the TypeScript dependency version to 4.4.
Starting from this version, the default catch variable type changes in TypeScript from any
to unknown
.
As a result, there need to be changes to the error handling code that did not involve instanceof
guards.
For example:
try {
await DataEndpoint.getViewData();
} catch (error) {
console.log(error.message); // Error TS2571: Object is of type 'unknown'.
if (error instanceof Error) {
console.log(error.message); // Works.
}
}
try {
await DataEndpoint.getViewData();
} catch (error: any) {
console.log(error.message); // Works, but using `any` is not recommended.
}
See also: the TypeScript change announcement.