How to run Vaadin in Jakarta EE Containers

In this tutorial we will learn how to create a Vaadin Flow project that we can run on any Jakarta EE Container such as WildFly or TomEE. We will start from a starter template and we will adapt it to create a sample Customer Form that binds its fields into the Database.

Setting up the Vaadin Flow Jakarta EE project

Firstly, if you are new to Vaadin Flow, we recommend heading first to this introduction article: Vaadin Tutorial: Building Modern Web Applications with Ease

In order to bootstrap a Vaadin Flow project which contains the right dependencies for a Jakarta EE container (WildFly), you can surf to the project initializer at: https://start.vaadin.com/app

vaadin wildfly jakarta ee tutorial

Expand the options by clicking on Edit and choose as Architecture “Jakarta EE“. Then, download the project.

A quick look at the project pom.xml reveals that, besides the Jakarta EE 10 dependencies and the general vaadin dependency, our project contains the vaadin-cdi dependency. This is essential to bridge the world of Vaadin Flow with Jakarta EE that is based on CDI:

<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>10.0.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <!-- Replace artifactId with vaadin-core to use only free components -->
    <artifactId>vaadin</artifactId>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-cdi</artifactId>
</dependency>

Besides, the project also includes WildFly Maven plugin, therefore will deploy our application to WildFly in a snap.

Coding our Vaadin Flow Route

The built-in project already contains a couple of example Classes:

src
├── main
│   ├── java
│   │   └── org
│   │       └── vaadin
│   │           └── example
│   │               ├── AppShell.java
│   │               ├── GreetService.java
│   │               └── MainView.java
  • The AppShell Class is essential for defining and configuring the Progressive Web App aspects of a Vaadin application. It sets up PWA-related metadata and defines the theme to be used for styling UI components across the application.
  • The MainView Class defines a Vaadin Flow Route with a minimal set of Components in it, to print an Hello Message.

In order to customize our project, we will customize the MainView Class. The new implementation will contain a Form with some fields that will be submitted to the back-end Service:

@Route("")
@CdiComponent
public class MainView extends VerticalLayout {

    @Inject
    private CustomerService service;
    private Binder<Customer> binder = new Binder<>(Customer.class);

    @PostConstruct
    public void init() {

        TextField firstName = new TextField("First Name");
        TextField lastName = new TextField("Last Name");
        TextField email = new TextField("Email");
        ComboBox<String> countryComboBox = new ComboBox<>("Country");
        countryComboBox.setItems("USA", "Canada"); // Add your country options here

        binder.bind(firstName, Customer::getFirstName, Customer::setFirstName);
        binder.bind(lastName, Customer::getLastName, Customer::setLastName);
        binder.bind(email, Customer::getEmail, Customer::setEmail);
        binder.bind(countryComboBox, Customer::getCountry, Customer::setCountry);

        Button registerButton = new Button("Register", event -> {

            Customer customer = new Customer();
            binder.writeBeanIfValid(customer);
            service.register(customer);

            // Perform registration logic here
            String message = "Registration successful for: " +
                    firstName.getValue() + " " +
                    lastName.getValue() + ", Email: " +
                    email.getValue();
            Notification.show(message);
            // Clear all fields after registration is completed
            binder.removeBean(); // Remove current bean from the binder
            binder.setBean(new Customer()); // Set a new instance of Customer to the binder
        });


        registerButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        registerButton.addClickShortcut(Key.ENTER);

        addClassName("centered-content");
        add(firstName, lastName, email, countryComboBox, registerButton);
    }

}

The most interesting addition is the use of the Binder Class. The Binder class in Vaadin is a crucial component used for binding data between UI components and Java objects. It plays a pivotal role in simplifying the process of synchronizing and validating data entered in UI components (like text fields, checkboxes, etc.) with corresponding data objects in Java.

In our example, by executing binder.writeBeanIfValid(customer), we copy the Form Components in a new Customer Object.

vaadin flow jakarta ee tutorial

Here is the Customer definition:

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private String email;
    // Getters / setters
}

Finally, once that we have all Customer properties in place, we can call the service.register(customer) that will persist the Customer in the Database:

@ApplicationScoped
public class CustomerService {
    @PersistenceContext
    EntityManager em;

    @Transactional
    public void register(Customer customer) {
        em.persist(customer);
    }
}

Running our Flow

Since the WildFly plugin is available, we can start WildFly and deploy the application as follows:

mvn install wildfly:deploy

The application will register on the root Web Context. Therefore we can access it at: http://localhost:8080:

You can experiment, by filling up the Form and clicking on the Register button. Verify that the operation completes successfully. For the sake of brevity, we didn’t discuss here the persistence.xml configuration of our application which uses just the H2 database. You can check the full source code at the end of this article.

Fixing the Error NoClassDefFoundError: com/sun/nio/file/ExtendedWatchEventModifier

By deploying the Vaadin starter on WildFly 30, I have hit the following error:

19:54:47,193 ERROR [com.vaadin.base.devserver.FileWatcher] (ForkJoinPool.commonPool-worker-18) Error starting file watcher: java.lang.NoClassDefFoundError: com/sun/nio/file/ExtendedWatchEventModifier

As discussed in this issue, this is related to a defect in the File Watcher when you are deploying a multi module project on WildFly. Until the issue is fixed, the workaround is to is to add com.sun.nio.file as a dependency.

Therefore, add the following configuration to your maven.war.plugin:

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
            <archive>
                <manifestEntries>
                    <Dependencies>jdk.unsupported</Dependencies>
                </manifestEntries>
            </archive>
        </configuration>
</plugin>

Conclusion

This article was a complete walkthrough the set up and creation of a complete Vaadin Flow project. We have covered the key aspects related to the creation of a Form with some components and how to bind them so that we can use as DTO for a Service Class. We also have discussed how to fix an issue related to the deployment on WildFly of the Vaadin Flow Jakarta EE project.

Source code: https://github.com/fmarchioni/mastertheboss/tree/master/web/vaadin/jakartaee

Found the article helpful? if so please follow us on Socials