Migration example - Bookstore Starter
This document shows an example of migration from a Vaadin 8 app to Vaadin 14. The migration process is done step-by-step and can be seen through the history of its GitHub repository. The idea is to keep the application compilable in order to be able to see the result of migrating steps.
Step 1 - Initial Vaadin Flow configuration
Maven
First of all, required maven dependency must be added to pom.xml. The Vaadin 8 dependencies, except vaadin-themes
, are kept for now and will be eliminated after the whole application is migrated. The only Vaadin platform dependency is the following:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<type>pom</type>
<scope>import</scope>
<version>${vaadin.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-core</artifactId>
</dependency>
</dependencies>
Starting from Vaadin 14, the vaadin-maven-plugin
should be configured for development time to make sure that all the needed resources are available for the development of the project. While it is not mandatory to have the plugin configured for all projects, it is needed for this migration so that necessary files are generated:
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-frontend</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
In this document, migrating custom components and extensions are not covered. So, the widgetset module that includes the following extensions is removed.
AttributeExtension
ResetButtonForTextField
UI class and Servlet configuration
Both
UI
class and Servlet configuration are optional in Vaadin Flow. However, we can keep them to leverage them in some cases e.g. controlling user access.Since the components are different, the DOM structure has changed. The new components are based on web components and a new theme. Thus the theming is discussed later.
In Vaadin Flow the locale is set automatically based on user preferred locale. So,
setLocale
can be removed.Best practice for setting page title is using
PageTitle
annotation on each view. So,getPage().setTitle
is removed fromMyUI::init
.All packages names in Vaadin Flow start with
com.vaadin.flow
. One way to correct them is to remove allimport
statements starting bycom.vaadin
and reimport Vaadin Flow classes. For example some equivalent classes in Vaadin Flow are:com.vaadin.ui.UI
→com.vaadin.flow.component.UI
com.vaadin.server.VaadinRequest
→com.vaadin.flow.server.VaadinRequest
com.vaadin.ui.TextField
→com.vaadin.flow.component.textfield.TextField
com.vaadin.ui.VerticalLayout
→com.vaadin.flow.component.orderedlayout.VerticalLayout
Test page
In order to verify that Vaadin Flow setup has been done correctly, a simple HelloWorldPage
like the following can be added.
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
@Route("")
@PageTitle("My")
public class HelloWorldPage extends Div {
public HelloWorldPage() {
this.add(new H1("Hello World!"));
}
}
@Route(“”)
shows that root path should be routed to this page. After running the application by mvn jetty:run
, the “Hello World!” message can be seen in the browser by entering this address: http://127.0.0.1:8080.
Step 2 - Access Control and Login Screen
VaadinServletConfiguration and UI class
In Vaadin Flow, defining a Servlet class is optional. So, we don’t have to create an extended class of VaadinServlet
, unless we need to change some configuration. Having a UI
class is optional too and this class can be removed as well because the UI
class is created by the framework. However, we may have some tasks assigned to our UI
class e.g. controlling access. In this example access control is moved to a more suitable place which is described in the following section.
Access Control
BeforeEnter
event of UI
class is a good place to control access and there is another event named UIInit
in VaadinService
class that is fired whenever a UI
is created. In order to leverage these events, we can create a class extended from VaadinServiceInitListener and add required code in serviceInit
method. The result looks like the following piece of code:
public class BookstoreInitListener implements VaadinServiceInitListener {
@Override
public void serviceInit(ServiceInitEvent initEvent) {
initEvent.getSource().addUIInitListener(uiInitEvent -> {
uiInitEvent.getUI().addBeforeEnterListener(enterEvent -> {
// Controlling access can be done here.
});
});
}
}
MyUI
class had an instance of BasicAccessControl
and other classes used it via its accessor; now after MyUI
class is eliminated, there must be another provider for AccessControl
implementation. The selected solution here is using a factory class (AccessControlFactory
).
CurrentUser
class is also needed to change because it is used in BasicAccessControl
class. We need to apply new packages names of Flow that start with com.vaadin.flow
. The same should be done in the next steps of migration.
LoginScreen
This is the first UI
screen migrated to 14. The following items describe what needs to be done in the migration process:
Instead of
CssLayout
another equivalent component must be used e.g.FlexLayout
or a simpleDiv
.Equivalent of
addComponent
method isadd
method.setWidth
method in Flow has only oneString
parameter that includes both measurement unit and width as a number e.g. “15em” or “310px”.Route
annotation determines the URL associated with this screen.Predefined style changes to components in 14 are referred to “theme variants”, and those change the
theme
attribute of the components instead of theclassName
. So,addStyleName(String)
can be replaced withaddThemeVariants(…)
. The available theme variants for components are showcased in the component demos. Changes in theming from V8 to Vaadin platform is described here.New
FormLayout
has a method namedaddFormItem
takes a component as a parameter and in addition to adding it to the form, it adds a label beside the component as well.Instead of
Button::setClickShortcut
the API is nowButton::addClickShortcut;
.
Some other changes that have been done are not related to Vaadin framework migration process; however, it is a good idea to do such refactorings at the same time as migration.
Step 3 - Menu, MainScreen and AboutView
Menu
As explained before, instead of CssLayout
, FlexLayout
is used.
Navigator
class is removed in Flow and this is one of many changes in routing and navigation since version 8. So, navigator
field is removed from Menu
. In addView
method it can be seen that navigation is done by RouterLink
component.
At this stage, a pretty look is not aimed for. It will be made nicer in later steps.
MainScreen
In Vaadin 8 version there is a CssLayout
that acts as a view container and navigation between different views is done inside the CssLayout
. In Vaadin Flow, parent layouts can be defined using a newly introduced RouterLayout
interface. Since MainScreen
is used as a layout for other views, it must implement RouterLayout
interface.
AboutView
Layout of views can be specified in Route
annotation like this @Route(value = "About", layout = MainScreen.class)
. We don’t need the HelloWorldPage
anymore, so it is removed and since it’s good to have a route to root path, RouteAlias
annotation is used to add a secondary path for AboutView
.
Another thing worth mentioning here is that in Vaadin platform, a component named Icon
is added and can be created by calling create
method of VaadinIcon
enum.
Here is the link to see the changes in step 3.
Step 4 - Product Grid
DataProvider
In Vaadin platform, when DataProvider::fetch
method is overridden, query.getOffset()
and query.getLimit()
must be used to fetch a specific chunk of data. If they are not used it shows that the returned data is incorrect and unexpected. To avoid such mistakes in implemented code, Vaadin platform throws an IllegalStateException
to show us what is wrong. So, ProductDataProvider::fetch
is fixed in order to use specified offset and limit. The data provider documentation for Vaadin platform can be found here.
ProductGrid
The following items briefly describe some of the changes in ProductGrid
.
There is no
HtmlRenderer
in Vaadin platform and it must be replaced by other renderers such asTemplateRenderer
orComponentRenderer
. In this migration,TemplateRenderer
is used. More info and guidance about all kinds of renderers can be found in “Using Renderers” section of Grid document. InTemplateRenderer
, apart from HTML markup, Polymer data binding notation can also be used. InProductGrid
, there are three TemplateRenderers:Price and StockCount columns leverage
TemplateRenderer
to align their text to the right.Availability column template uses a Vaadin component named
iron-icon
to show a circle colored based on availability value. In order to set different styles to the circle, three CSS classes with equivalent names to three values of availability (Available
,Coming
andDiscontinued
) are defined in a CSS file (grid.css). Also, the dependency of the grid on the CSS file is defined by addingCssImport
annotation toProductGrid
class.
Grid.Column::setCaption
method is renamed tosetHeader
.setFlexGrow
method is called for each column to set grow ratios of them.
SampleCrudView
This is the page that includes ProductGrid
and ProductForm
and since ProductForm
is going to be migrated in the next step, the parts of the code related to it are commented. Like in the other views, a Route
annotation is added here with the “Inventory” value. Also, as this view is the main view of the project, the route to the root path, the RouteAlias
annotation, should be moved here. Other changes in SampleCrudView
are the following items.
getElement().getThemeList()::add
is used to add a theme variant to a component. An improved API for this has been released in V12.In Vaadin 8, to get the parameters passed via the URL,
View
interface must be implemented and theenter
method must be overridden. In Vaadin platform, there is an interface namedHasUrlParameter
that does the job. It is generic, so parameters are safely converted to the given types. More information about URL parameters can be found here.Instead of using
HorizontalLayout::setExpandRatio
,HorizontalLayout::expand
method is used.
Here is the link to see the changes in step four.
Step 5 - Product Form
Since after this step, all Java code is migrated to Vaadin platform, it is time to remove Vaadin 8 dependencies. Besides, keeping both versions may cause some conflicts in their dependencies e.g. jsoup
. So, vaadin-server
and vaadin-push
are removed from pom.xml. Other changes in this step are as follows.
ProductForm Design
The following items are some of the changes from Vaadin 8 to Vaadin platform in design files.
In Vaadin 8, Vaadin Designer uses HTML markups to store designed views and they are stored in files with html extension. However, the tags that are used by Vaadin Designer are not standard HTML tags. So, these html files cannot be correctly shown and rendered by browsers. While in Vaadin platform, Polymer template is used to define views and Vaadin Designer also uses it to store designed views.
Prefix of the Vaadin components names is changed from
v
tovaadin
.For customizing the look and feel of the components using the provided theme variants, the variants are applied with the
theme
attribute, instead of thestyle-name
(class name). E.g.
Vaadin 8 version:
<v-button style-name="primary" _id="save">Save</v-button>
Vaadin platform version:
<vaadin-button theme="primary" id="save">Save</vaadin-button>
ProductForm Java Class
ProductFormDesign
class is removed and its content is moved to ProductForm
class. Actually, this is the recommended pattern in Vaadin platform and it is also supported by Vaadin Designer. In Vaadin 8, Vaadin Designer keeps two classes, a superclass for designer generated code and an inherited class for the code implemented by the developer. The following items are some of the changes in ProductForm
.
JsModule
and Tag annotations are the required annotations to connectProductForm
class to its design file, ProductFormDesign.html. And unlike Vaadin 8, reading the design file is done automatically and there is no need to callDesign.read
.Id
annotation is used to connect fields to their equivalents in the associated polymer template.In
ComboBox
,setEmptySelectionAllowed
method is renamed tosetAllowCustomValue
.
ErrorView
Router Exception Handling in Vaadin Flow is described here. Applications can have different views for catching different exceptions. For example, ErrorView
catches NotFoundException
that is thrown when something goes wrong while resolving navigation routes. And unlike Vaadin 8, there is no need to register ErrorView
in a navigator
or something like that. It is automatically detected and is used by Flow.
SampleCrudLogic
Apart from some cleaning, a small change that is worth mentioning is the change in how the URL of the browser is updated. In Vaadin 8, page.setUriFragment
is called and the new URL must be constructed and passed as a parameter. While in Vaadin Flow, it is done more elegantly; navigate
method of UI
class is called and the view parameter is passed as a parameter to navigate
method.
Step 6 - Production Mode
In Vaadin 14 the production mode is recommended to be enabled by is adding a profile to pom.xml
. All old V8 related production build configuration can be removed. The following code shows the required configuration for enabling a production build in 14 when running the command mvn package -Pproduction
:
<profiles>
<profile>
<!-- Production mode is activated using -Pproduction -->
<id>production</id>
<properties>
<vaadin.productionMode>true</vaadin.productionMode>
</properties>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>flow-server-production-mode</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
For further details on production mode in 14, you can read here.
Step 7 - Theming the application
There is currently no example on migrating from an existing Vaadin 7 or 8 theme to Vaadin 14 Lumo theme. The component set is different, so the styling cannot be applied out-of-the-box to newer versions.
Thus it is recommended to switch to using the new Lumo theme, and customizing the look and feel on top of that. For more information, check the Themes and Styling documentation.