Jakarta EE and CDI

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.

Vaadin Flow runs on any Servlet 6 (Jakarta EE 10) container. On a full Jakarta EE server the vaadin-cdi add-on gives views CDI injection and adds CDI-aware scopes, mirroring what the Spring starter does. This page follows the CDI integration guide. For the Spring equivalent, see Spring Boot Integration.

The add-on and packaging

<dependency>
  <groupId>com.vaadin</groupId>
  <artifactId>vaadin-cdi</artifactId>
</dependency>

<packaging>war</packaging>

A beans.xml under src/main/webapp/WEB-INF (or src/main/resources/META-INF) activates CDI. Build with mvn package and deploy the WAR to WildFly, Open Liberty, Payara, GlassFish or TomEE. No web.xml is needed — the add-on registers the Vaadin servlet.

CDI bean scopes

Scope One instance per…

@VaadinServiceScoped

VaadinService — effectively application-wide

@VaadinSessionScoped

user session

@NormalUIScoped

UI (browser tab); @UIScoped is the pseudo-scoped variant

@RouteScoped + @RouteScopeOwner(View.class)

active route target

@RouteScoped
@RouteScopeOwner(OrderView.class)
public class OrderContext {
    private Order current;
    // shared by OrderView and its child components, cleared on navigation away
}

Injection and events

@Route("customers")
public class CustomerListView extends VerticalLayout {

    @Inject
    public CustomerListView(CustomerService service, Event<CustomerSelected> selected) {
        Grid<Customer> grid = new Grid<>(Customer.class);
        grid.setItems(service.findAll());
        grid.asSingleSelect().addValueChangeListener(e ->
                selected.fire(new CustomerSelected(e.getValue())));
        add(grid);
    }
}

@ApplicationScoped
public class AuditListener {
    void onSelected(@Observes CustomerSelected event) { /* ... */ }
}

A JPA CRUD

With a container-managed EntityManager:

@Stateless
public class CustomerRepository {

    @PersistenceContext
    EntityManager em;

    public List<Customer> findAll() {
        return em.createQuery("select c from Customer c", Customer.class).getResultList();
    }

    public Customer save(Customer c) {
        return c.getId() == null ? persist(c) : em.merge(c);
    }

    private Customer persist(Customer c) { em.persist(c); return c; }
}

The view wires this to a Grid and a Binder exactly as in the Spring example; see Data Persistence for lazy loading and transactions, and the SQL Reference for the queries.

Quarkus

The vaadin-quarkus extension runs Flow on Quarkus with the same CDI scopes and supports dev mode and native image:

<dependency>
  <groupId>com.vaadin</groupId>
  <artifactId>vaadin-quarkus-extension</artifactId>
</dependency>

Legacy integrations

Vaadin 7’s portlet (Liferay / GateIn) and OSGi deployment models still exist as separate add-ons (vaadin-portlet, vaadin-osgi-integration) for maintaining older systems, but a new application should target a plain Servlet container or Spring Boot. They are not covered further here.

See also