Release 3.1

Jmix 3.1 is currently available only as a release candidate. To work with it, use Studio 3.1 from the nightly channel as described in Nightly Builds.

The documentation is being updated for this release.

How To Upgrade

To create new projects with Jmix 3.1 or to upgrade an existing project, you need Studio 3.1 or newer, so update your Jmix Studio plugin first.

Jmix Studio 3.1 requires IntelliJ IDEA 2026.1 or newer.

See Upgrading Project section for how to upgrade your project using Studio. The automatic migration procedure makes the following changes in your project:

  • Updates the version of Jmix BOM which in turn defines versions of all dependencies.

  • Updates the version of Jmix Gradle plugin.

  • Updates Gradle wrapper to 9.8.0

See also the full list of breaking changes that can affect your project after the upgrade.

Updated Dependencies

The following major dependencies have been updated:

  • Spring Boot 4.1

  • Vaadin 25.3

New Features and Improvements

Jmix CLI

Jmix CLI is a new command-line tool that creates Jmix projects without an IDE: in a terminal, in a script, or by an AI coding agent. It uses the same project templates as Studio and adds the Jmix Agent Toolkit to the created project. See Using Jmix CLI for how to install and use it.

Studio Improvements

  • The view creation wizard has a new step for list and master-detail views where you select how users filter the data: genericFilter (the default), a set of propertyFilter components for the attributes you select, fullTextFilter if the Search add-on is included in the project, or no filter.

  • The entity designer lets you define the @LookupField annotation for an entity and for its reference attributes. The view creation wizard takes this annotation into account when it generates components for references.

  • The new Views with Attribute action of the entity designer shows the view components bound to an entity attribute and opens the view descriptor at the selected component. It also lets you add the attribute to the views of the entity. The action is available on the attributes table toolbar and in each attribute row.

  • The new Copy View action creates a copy of a view with its controller, descriptor and messages.

  • The dialog that lists Liquibase changelogs not yet applied to the database now shows the content of the selected changelog. You can use it to review changelogs that come from add-ons.

  • The JPQL designer can be opened from the gutter icon for queries in LoadContext.Query and in the setQueryString() method.

  • Studio inspections check the structure of reports defined in Java code that have a streaming band. They report a structure that the reporting engine does not support, for example, a second streaming band, a child band of a streaming band or a dataset that is not SQL or JPQL.

New AI Chat Add-on

The new AI Chat add-on provides UI components for building AI chat interfaces. The answers come from an LLMProvider that the application implements, so the components work with Spring AI, a vendor SDK, or your own service.

  • aiChat is a complete chat with streaming answers, Markdown messages, file attachments and per-message actions. It can be bound to a collection container of your own message entity to save the conversation.

  • aiMessageList and aiMessageInput can be used on their own to build a chat that aiChat does not cover.

  • aiCodeBlock shows source code in chat messages and in any other view.

New UI Recovery Add-on

The new UI Recovery add-on keeps unsaved changes of views when the server node restarts, the HTTP session expires, or the browser closes. It saves the changes to the database as a draft while the user works, and offers to restore the draft when the user opens the view again. Drafts are available in a cluster and after a full restart of the application.

Dynamic Model Add-on

The Dynamic Model add-on is no longer experimental. It has the following new features:

AI Tools Add-on

The AI Tools add-on has the following new features:

  • The new @ExcludeFromAi annotation hides an entity or an attribute from the Data Load tools at the code level. Unlike the jmix.aitools.dataload.* include and exclude properties, the annotation cannot be overridden at deployment time, so the hidden data can be exposed only by changing the code and rebuilding the application.

  • The chat UI sets conversation titles automatically. By default, the first user message becomes the title. With the new jmix.aitools.ui.conversation-title-mode property, the model can generate a short title instead, or the conversation can keep the default title.

BPM Add-on

The BPM add-on has the following new features in the BPMN modeler:

  • You can edit the History level of a process along with other process properties. The selected level overrides the history level of the process engine.

  • You can set the flowable:exclusive, flowable:asyncLeave, and flowable:asyncLeaveExclusive attributes for tasks, embedded subprocesses, call activities, gateways, and most events. For user tasks, gateways, and events, flowable:async is now available as well. See Asynchronous Execution Properties.

  • You can add escalation events to processes, set their properties, and manage Escalation definitions in the process properties.

Reports Add-on

The Reports add-on has the following new features:

  • A report band can now be streaming: its rows are read from a database cursor and written to the XLSX document one by one instead of being loaded into memory. To make a band streaming, select its Streaming checkbox in the report detail view or set streaming = true in the @BandDef annotation.

  • The new AI-generated JPQL dataset type lets you describe band data in natural language. In the report detail view, an LLM generates a JPQL query from the prompt, and the view stores it in the report definition. A report run executes the stored query through DataManager and applies the data access permissions of the current user.

Grouping Data Grid Add-on

You can preserve the applied column header filters in URL query parameters by adding the groupDataGridFilter element to the urlQueryParameters facet.

Email Sending Add-on

The Email Sending add-on simplifies setting up OAuth2 authentication with Google and Microsoft mail servers:

  • The new Email connection view replaces the OAuth2 token view. It connects a mailbox account using the authorization code flow or, for Microsoft, the device code flow, and stores the refresh token. The view also shows the connection parameters and tests the connection to the mail server.

  • The new jmix.email.oauth2.redirect-uri property sets the redirect URI of the authorization code flow, for example, when the application runs behind a reverse proxy.

  • The add-on sets the XOAUTH2 authentication mechanism itself, so you don’t need to add it to spring.mail.properties.*.

Read Views

The new read views show an entity instance that users cannot edit. A read view extends StandardReadView, loads the entity by its id, and always has a read-only DataContext.

  • You can create read views in Studio using the Entity read view and DTO entity read view templates of the view creation wizard.

  • You can open read views using the ViewNavigators and DialogWindows beans, and using the ViewBuilders bean of the Tabbed Application Mode add-on.

  • If an entity has a read view, the list_read action opens it instead of the detail view in read-only mode. The new entity_read action shows the entity selected in an entity picker.

  • The @ReadViewTemplate annotation generates a read view for an entity at runtime. The Dynamic Model add-on generates read views for dynamic entities that declare a view of the read type.

Resizable Side Panel

Users can now resize the sidePanelLayout component at runtime by dragging the handle on the side panel’s inner edge. Resizing works for horizontal and vertical positions and respects the configured minimum and maximum sizes. The settings facet can save and restore the size selected by the current user.

SVG Component

The new svg component renders SVG markup directly in the view. The markup can be set in the nested content element, loaded from a file using the file attribute, or set in the view controller.

Popover Component

The new popover component is an overlay that opens next to a target component and can contain any components. You can declare it in a view or fragment descriptor and set the target attribute to the id of a component. The popover can open on a click, on hover or on focus, or from the view controller, and it can be modal.

Popover Renderer for Data Grid

The new popover renderer shows long text in a dataGrid column. The cell text is cut with an ellipsis if it does not fit, and a click on the cell shows the full text in a popover. Add the popoverRenderer element to a column in XML or create PopoverRenderer in Java.

Lookup Field Annotation

The new @LookupField entity annotation defines the component that the framework generates for selecting a reference: an entityComboBox with a drop-down list or an entityPicker that opens a lookup view. It is used in genericFilter and propertyFilter parameters, editable dataGrid cells and runtime view templates. Put it on an entity class to apply it to all references to the entity, or on a reference attribute to apply it to this attribute only. You can also set the actions of the component and load the drop-down items in pages while the user types, using a JPQL query or a search by the instance name.

The itemsQuery element of entityComboBox has the new byInstanceName attribute that finds items by the instance name without a JPQL query.

Breaking Changes

Vaadin 25.3

The update to Vaadin 25.3 brings the following changes (see #5720):

  • The image component can’t contain other components anymore. JmixImage doesn’t have the setText()/getText(), setWhiteSpace(), setEnabled()/isEnabled(), add() and remove() methods. In XML, the enabled, text and whiteSpace attributes and nested components of image are ignored.

  • The protected JmixMenuBarRootItem.updateClassName() method is removed.

  • InMemoryUploadHandler and FileTemporaryStorageUploadHandler now extend Vaadin’s AbstractUploadHandler instead of TransferProgressAwareHandler. FileTemporaryStorageUploadHandler deletes the temporary file when an upload fails or is rejected, and its getFileInfo() method returns null until the current upload creates the file.

  • In the Tabbed Application Mode add-on, the @Push configuration of the app shell is applied before UIInitListener listeners are called, so a listener can override it.

  • Anchor.setHref() and IFrame.setSrc(), as well as the href and src XML attributes of anchor and iframe, throw IllegalArgumentException for a URL scheme that Vaadin doesn’t consider safe, for example javascript:. Add the scheme to the Vaadin safeUrlSchemes configuration parameter, or use setUnsafeHref() and setUnsafeSrc() in code.

  • addThemeName("") throws IllegalArgumentException.

  • TreeGrid methods expand(), collapse(), expandRecursively() and collapseRecursively() now take Collection<? extends T> and Stream<? extends T> parameters. Update the signatures of these methods if you override them in a TreeDataGrid subclass.

  • Many VaadinIcon constants and the corresponding JmixFontIcon constants are deprecated. setRole() of JmixSideDialog is deprecated in favor of setAriaRole(), and withOverlayRole() of Dialogs.SideDialogBuilder is deprecated in favor of withAriaRole().

AI Tools Add-on

  • Rows of JpqlExecutionResult.getRows() and EntityDataLoadResult.getRows() now contain null for a column that has no value (see #5598). Before, such a column contained an empty string. The rows that tools return to the model also contain null instead of an empty string. The method signatures are the same, so the compiler doesn’t show the places to fix. Check the values for null when you read the rows:

    EntityDataLoadResult result = aiDataLoadService.loadData("customers with their email");
    for (Map<String, Object> row : result.getRows()) {
        Object email = row.get("email");
        String text = email != null ? email.toString() : ""; // email can be null
    }
  • EntityDataLoadResult.getQuery() now returns the query that was actually executed or failed validation (see #5749). If the generated query was repaired, the method returns the repaired query, and its explanation, warnings, maxResults and firstResult come from the repair. The original query generated by the LLM isn’t available from the result.

  • The AiChatMessageService interface has a new loadLatestMessages() method (see #5649). If you have your own implementation of this interface, implement the method. The chat hub now orders and groups conversations by the time of the last message instead of the creation time.

  • A new conversation now gets the first user message as its title (see #5648). Before, it kept the New AI Conversation title. If your code gives a conversation its own title before the first message, the first message replaces this title. To keep your title, call setTitleMode(AiConversationTitleMode.NONE) on the AiChatFragment that shows the conversation. To keep the previous behavior in the whole application, set the jmix.aitools.ui.conversation-title-mode property to NONE.

Charts Add-on

The Charts add-on now uses Apache ECharts 6.1 instead of 5.4 (see #5699). Existing views work without code changes, but charts may look different:

  • The default theme has a new color palette and spacing. The legend is at the bottom center, and the title is at the top center. To get a look closer to the previous version, set colorPalette="#5470c6, #91cc75, #fac858, #ee6666, #73c0de, #3ba272, #fc8452, #9a60b4, #ea7ccc" on charts:chart, top="0" on charts:legend, and left="0" top="0" on charts:title. Check charts that have components at the top or at the bottom, for example a slider dataZoom: they may overlap the title or the legend.

  • Axis labels and names are kept inside the chart, and axis names are moved so that they don’t overlap axis labels. To return to the previous behavior, set outerBoundsMode="NONE" on charts:gridItem or nameMoveOverlap="false" on the axis.

  • Rich text styles inherit the font and text shadow settings of the plain label. To return to the previous behavior, add "richInheritPlainLabel": false to nativeJson.

  • Bar, pictorialBar, candlestick and boxplot shapes don’t go outside the grid anymore. To return to the previous behavior, set containShape="false" on the axis.

  • The second argument of a tooltip valueFormatter function is now the index in the original series data, not the index after dataZoom filtering. Update your JavaScript functions that use it.

  • Grid.containLabel is deprecated. Use outerBoundsMode="SAME" together with outerBoundsContain="AXIS_LABEL" instead. When containLabel is enabled, the outerBounds* options are ignored.

Email Sending Add-on

  • The OAuth2 token view is replaced with the new connection view, and its id is changed from email_tokenView to email_connectionView (see #5546). The old email/token route still works. Replace the old view id in:

    • menu.xml, if your application uses the single menu mode. Otherwise, the main view fails with NoSuchViewException.

    • @ViewPolicy and @MenuPolicy annotations of your resource roles. Otherwise, users lose access to the view.

  • The add-on doesn’t define the mailSendTaskExecutor bean anymore (see #5703). Before, Vaadin could use this bean for its asynchronous work, and the application failed to start if it had another TaskExecutor bean. Now:

    • Code that injects the mailSendTaskExecutor bean by name fails at startup with NoSuchBeanDefinitionException. Remove such injections.

    • Your own bean named mailSendTaskExecutor doesn’t replace the email sending pool anymore. The add-on ignores it and logs a warning at startup.

    • @Async methods and Vaadin asynchronous tasks run on the applicationTaskExecutor bean of Spring Boot instead of the email sending pool. This pool has a different size and an unbounded queue.

  • When OAuth2 authentication is enabled, the add-on checks the configuration more strictly (see #5539):

    • The spring.mail.password property is ignored, and the add-on logs a warning. Before, a password set together with OAuth2 authentication made the add-on use basic authentication.

    • The application fails to start if spring.mail.username, jmix.email.oauth2.client-id or jmix.email.oauth2.secret is not set. Before, these errors appeared only when an email was sent.

Maps Add-on

Deleting map objects is now controlled separately from modify mode by the featureDeleteEnabled attribute of a vector source (see #5576):

  • A source with featureModifyEnabled="true" doesn’t show the Delete action by default anymore. Set featureDeleteEnabled="true" on the source, or set the jmix.maps.ui.feature-modify-includes-delete application property to true to keep the previous behavior for all sources that don’t set featureDeleteEnabled.

  • SourceFeatureDeleteEvent and addSourceFeatureDeleteListener() are moved from HasFeatureModify to HasFeatureDelete. Replace HasFeatureModify.SourceFeatureDeleteEvent with HasFeatureDelete.SourceFeatureDeleteEvent in your code.

OIDC and SAML Add-ons

The following elements of the auto-configuration are renamed (see #5484):

  • OidcAutoConfiguration.DefaulOidcVaadinWebSecurity → DefaultOidcVaadinWebSecurity

  • SamlAutoConfiguration.DefaulSamlVaadinWebSecurity → DefaultSamlVaadinWebSecurity

  • The claimsRoleMapper bean in SamlAutoConfiguration → samlAssertionRolesMapper

Update the code that extends these classes or refers to the bean by name.

Reports Add-on

Unused code that came from the YARG library is removed from the Reports add-on (see #2774):

  • The io.jmix.reports.yarg.loaders.impl.GroovyDataLoader class. The add-on uses JmixGroovyDataLoader for the groovy loader type. Unlike the removed class, it checks the jmix.core.unsafe-runtime-features-enabled and jmix.reports.groovy-enabled properties.

  • The InitializationException and ReportingXmlException classes from the io.jmix.reports.yarg.exception package.

  • The update() and batch() methods of io.jmix.reports.yarg.util.db.QueryRunner. Use Spring JdbcTemplate or JDBC instead.

  • The commitAndClose(), commitAndCloseQuietly(), rollback(), rollbackAndClose(), rollbackAndCloseQuietly(), loadDriver(), printStackTrace() and printWarnings() methods of io.jmix.reports.yarg.util.db.DbUtils.

  • The UnoConverter.createAny(Object) method. Use new Any(new Type(XCell.class), value) instead.

  • The AbstractFormatter.SIMPLE_ALIAS_REGEXP and DataExtractorImpl.EMPTY_MAP fields.

Dynamic Model Add-on

The Dynamic Model add-on now reads the YAML model definition strictly (see #5731). The rules are described in Writing YAML by Hand.

This affects only models that were written or edited by hand in the Code presentation. Models saved from the visual editor always have quoted values and are read as before.

Loaded State of Entity References

An entity instance returned by DataManager.getReference() now reports as loaded only its id and the attributes set on it later (see #5660). Before, EntityStates.isLoaded() returned true for every attribute of such an instance.

Now for a reference:

  • isLoaded() returns false for all attributes except the id and the attributes set after creation.

  • isLoadedSafe() returns YES or NO and doesn’t call getters.

  • isLoadedWithFetchPlan() returns false for a fetch plan that contains other attributes.

  • getCurrentFetchPlan() returns a fetch plan with the id and the attributes set after creation.

This has the following visible effects:

  • A reference is serialized (in REST, BPM process variables, etc.) with only its id and the attributes set on it.

  • A reference doesn’t have the default values assigned on creation in @PostConstruct methods or field initializers.

  • DataContext.merge() of a reference into a context that has the loaded instance doesn’t replace loaded values with nulls.

If your code relied on a reference reporting all attributes as loaded, update it.

Changelog

  • Resolved issues in Jmix Framework:

  • Resolved issues in Jmix Studio: