Migration example - Bookstore Starter
- Step 1 - Initial Vaadin Flow configuration
- Step 2 - Access Control and Login Screen
- Step 3 - Menu, MainScreen and AboutView
- Step 4 - Product Grid
- Step 5 - Product Form
- Step 6 - Production Mode
- Step 7 - Theming the application
This document shows an example migration from a V8 app to Vaadin Flow. 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:
Source code
XML
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-core</artifactId>
<version>LATEST</version>
</dependency>In this document, migrating custom components and extensions is not covered. So, the widgetset module that includes the following extensions is removed.
-
AttributeExtension -
ResetButtonForTextField
UI class and Servlet configuration
-
Both
UIclass 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,
setLocalecan be removed. -
Best practice for setting page title is using
PageTitleannotation on each view. So,getPage().setTitleis removed fromMyUI::init. -
All packages names in Vaadin Flow start with
com.vaadin.flow. One way to correct them is to remove allimportstatements starting bycom.vaadinand 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.
Source code
Java
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.
Here is the link to the repository after the first step.
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:
Source code
Java
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 next
steps of migration.
LoginScreen
This is the first UI screen migrated to Flow. The following items
describe what needs to be done in migration process:
-
Instead of
CssLayoutanother equivalent component must be used e.g.FlexLayoutor a simpleDiv. -
Equivalent of
addComponentmethod isaddmethod. -
setWidthmethod in Flow has only oneStringparameter that includes both measurement unit and width as a number e.g. “15em” or “310px”. -
Routeannotation determines the url associated with this screen. -
In order to add a theme variant in V10,
getElement().getThemeList().add(String)is used. Although theme variant is different from style name, the former can be considered as the successor of the latter. So,addStyleName(String)can be replaced withgetElement().getThemeList().add(String). However, in V12addThemeVariants(…)API was reintroduced for generated components. Changes in theming from V8 to Vaadin platform is described here. -
New
FormLayouthas a method namedaddFormItemtakes a component as a parameter and in addition to adding it to the form, it adds a label beside the component as well. -
In Flow, instead of
Button::setClickShortcutthat adds a shortcut key to a button, a keypress event listener should be added. For example, the following piece of code is equivalent tologin.setClickShortcut(ShortcutAction.KeyCode.ENTER);.
Source code
Java
loginForm.getElement()
.addEventListener("keypress", event -> login())
.setFilter("event.key == 'Enter'");An improved keyboard shortcuts API will be available in Vaadin 13.
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.
Here is the link to see the changes in second migration step.
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 and 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
HtmlRendererin Vaadin platform and it must be replaced by other renderers such asTemplateRendererorComponentRenderer. In this migration,TemplateRendereris 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
TemplateRendererto align their text to right. -
Availability column template uses a Vaadin component named
iron-iconto 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,ComingandDiscontinued) are defined in a css file (grid.css). Also, the dependency of the grid on the css file is defined by addingStyleSheetannotation toProductGridclass.
-
-
Grid.Column::setCaptionmethod is renamed tosetHeader. -
setFlexGrowmethod 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 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 root path, the RouteAlias annotation,
should be moved here. Other changes in SampleCrudView are the following
items.
-
getElement().getThemeList()::addis used to add a theme variant to a component. An improved API for this has been released in V12. -
In Vaadin 8, in order to get the parameters passed via the URL,
Viewinterface must be implemented and theentermethod must be overridden. In Vaadin platform, there is an interface namedHasUrlParameterthat 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::expandmethod 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
vtovaadin. -
For customizing the look and feel of the components using the provided theme variants, the variants are applied with the
themeattribute, instead of thestyle-name(class name). E.g.
Vaadin 8 version:
Source code
HTML
<v-button style-name="primary" _id="save">Save</v-button>Vaadin platform version:
Source code
HTML
<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 developer. The following
items are some of the changes in ProductForm.
-
HtmlImportand Tag annotations are the required annotations to connectProductFormclass to its design file, ProductFormDesign.html. And unlike Vaadin 8, reading the design file is done automatically and there is not need to callDesign.read. -
Idannotation is used to connect fields to their equivalents in the associated polymer template. -
In
ComboBox,setEmptySelectionAllowedmethod is renamed tosetAllowCustomValue. -
CheckboxGrouphas been released in Vaadin 12.
The commit showing the changes for a migrated product form is here.
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.
The commit showing the migration of the error view is here.
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 in a more elegant
way; navigate method of UI class is called and the view parameter is
passed as a parameter to navigate method.
Here is the link to see all changes in step five.
Step 6 - Production Mode
The best practice to have the production mode in Vaadin Flow is adding a profile to pom.xml. So, the production module is no longer needed and is removed and a profile named productionMode is added to pom.xml of ui module. In terms of production mode, there are some differences between Vaadin 8 and Flow. The new production mode of Flow is fully described Here.
Here is the link to see all changes in step six.
