What’s New
This section covers new features of Jmix framework and Studio 2.2, as well as some breaking changes to be aware of when upgrading from a previous version of the framework.
How To Upgrade
To create new projects with Jmix 2.2 or to upgrade an existing project, you need Studio 2.2 or later, so update your Jmix Studio plugin first. The minimal supported IntelliJ IDEA version is now 2023.2. |
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 the version of Gradle wrapper to 8.6 in
gradle/wrapper/gradle-wrapper.properties
. -
In Kotlin projects, updates the version of Kotlin plugin to 1.9.22.
-
Due to relocation of the pessimistic locking feature, replaces usages of
io.jmix.core.pessimisticlocking
package withio.jmix.pessimisticlock
, replacesjmix.core.pessimistic-lock.*
application properties withjmix.pslock.\*
and adds dependencies to the new add-on tobuild.gradle
. -
Adds
jmix.ui.view.prevent-browser-tab-closing = true
application property. See below for more information. -
Adds
spring.main.allow-circular-references = true
application property. See below for more information. -
Adds
jmix.core.skip-null-or-empty-conditions-by-default = true
application property. See below for more information. -
Adds
jmix.appsettings.check-permissions-for-app-settings-entity = true
application property if the project includes the Application Settings add-on. See below for more information.
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 3.2. See its release notes for more information.
-
Vaadin 24.3. See release notes for Vaadin 24.2 and 24.3 for more information. Studio removes the
.pnpmfile.cjs
file from your project when migrating it to Jmix 2.2 (because of vaadin/flow#17873). Make sure this file doesn’t exist after migration.
New Features and Improvements
Support for Java 21
You can now use Java 21 and all its language features to write your applications.
The framework is still built using Java 17, so both Java 17 and 21 are available for application projects.
Charts Add-on
The new Charts add-on integrates the Apache ECharts JavaScript library into Jmix UI.
See the Charts documentation and issue #2437 for more information.
Maps Improvements
-
Added support for clustering and heatmaps. See High-Density Data Visualization.
-
Added support for MultiPoint, MultiPolygon and MultiLineString. See #2807.
BPM Improvements
-
The BPM form wizard in Studio now supports creating forms for Start events and using entity instances instead of process variables. See the Form template and Form type dropdowns on the first step of the wizard.
-
The Async flag can be set for service tasks in the Studio BPMN designer.
-
Business process definitions developed in Studio can now be deployed to the running application. Use the Hot Deploy Process button in the top panel of the BPMN designer in Studio.
-
The runtime BPM modeler now provides support for the
flowable:failedJobRetryTimeCycle
element. See the Failed job retry time cycle property when a service task is selected. -
The runtime BPM modeler now allows you to select existing process variables for bean arguments from dropdowns.
RichTextEditor Component
The new richTextEditor
component integrates the Quill JavaScript library into Jmix UI. It’s available in the standard Add component palette.
Horizontal Main Menu
The new horizontalMenu
component allows you to create a main view with a horizontal menu.
The new Main view with top menu template is available in the view creation wizard. If you want to use the new view instead of the existing main view, select the Use as default main view checkbox on the first step of the wizard. Then Studio will replace the layout
attribute of the @Route
annotation in all views and set the new view in the jmix.ui.main-view-id
application property.
See #2492 for more information.
Filtering Main Menu
The new menuFilterField
component allows users to filter main menu items. It’s available in the standard Add component palette.
The menu
attribute should point to a listMenu
component to be filtered:
<menuFilterField menu="menu"
placeholder="Search..." classNames="ms-s me-s"/>
<nav id="navigation" classNames="jmix-main-view-navigation" ariaLabel="msg://navigation.ariaLabel">
<listMenu id="menu"/>
</nav>
Please note that filtering of Horizontal Main Menu is not supported.
Initial Layout in Main View
Now you can declaratively define an initial layout that will be shown when no views are opened in the main view. Use the initialLayout
element of the appLayout
component:
<appLayout>
<navigationBar .../>
<drawerLayout .../>
<initialLayout>
<h2 text="Hello world!"/>
</initialLayout>
</appLayout>
See #2213 for more information.
Data Grid Improvements
URL Parameters for Filter in Column Headers
The dataGrid column header filter can now be reflected in URL to provide a deep link and to save the view state when navigating to a detail view and back.
Use the dataGridFilter
element of the urlQueryParameters facet, pointing to the data grid:
<facets>
<urlQueryParameters>
<dataGridFilter component="usersDataGrid"/>
</urlQueryParameters>
</facets>
<layout>
<dataGrid id="usersDataGrid" dataContainer="usersDc">
<columns>
<column property="username" filterable="true" resizable="false" autoWidth="true"/>
Column Visibility Control
The new gridColumnVisibility
component allows users to hide and show columns of a data grid. It consists of a button and a dropdown menu with the list of columns.
Usage example:
<hbox id="buttonsPanel" classNames="buttons-panel">
<!-- ... -->
<gridColumnVisibility icon="COG" themeNames="icon"
dataGrid="usersDataGrid" exclude="picture"/>
</hbox>
<dataGrid id="usersDataGrid" dataContainer="usersDc">
<columns resizable="true">
<column key="picture" sortable="false" flexGrow="0" resizable="false"/>
<column property="username"/>
<column property="firstName"/>
Collection Properties in Generic Filter
The genericFilter component now allows you to create conditions for collection (to-many) properties.
For example, in the Onboarding application, you can filter Users by the steps
property and its nested properties: steps.dueDate
, steps.step.name
, etc. The JPA data store will automatically create an appropriate JPQL query with the join
clause. Previously, you could achieve this only by defining a JPQL condition manually.
See #518 for more information.
Sending Events to All User Sessions
The UiEventPublisher
bean now has the publishEventForUsers()
method that accepts an application event instance and a collection of usernames. This method allows you to send events to user session of particular users, regardless of whether they are connected to the same server or a different server within the cluster.
Example of sending an event to alice
:
public class DepartmentListView extends StandardListView<Department> {
@Autowired
private UiEventPublisher uiEventPublisher;
@Subscribe(id = "sendEventBtn", subject = "clickListener")
public void onSendEventBtnClick(final ClickEvent<JmixButton> event) {
uiEventPublisher.publishEventForUsers(new MyUiEvent(this), List.of("alice"));
}
public static class MyUiEvent extends ApplicationEvent {
public MyUiEvent(Object source) {
super(source);
}
}
}
Example of an event listener:
public class MainView extends StandardMainView {
@Autowired
private Notifications notifications;
@EventListener
public void onMyUiEvent(DepartmentListView.MyUiEvent event) {
notifications.show("Event received");
}
}
If the second argument of the publishEventForUsers()
method is null, the event is sent to all connected users.
See #1235 for more information.
Improved Save Performance
Now edited entity is not reloaded by default after save-and-close action if the detail view was opened by navigation, because in this case the list view reloads the whole list anyway. It improves the performance for complex views that load and save large object graphs.
You can control the reloading of saved instances explicitly using the setReloadSaved()
method of the DetailView
interface, for example:
@Subscribe
public void onInit(final InitEvent event) {
setReloadSaved(true);
}
See potentially breaking changes and #1725 for more information.
Reduced Build Time
The build process now skips enhancing entities if they have not been modified since the last build, which significantly reduces build time for projects with a large data model.
For example, if you have built your project, then you modify a view controller and build again, you should see the following message in the console: Entities enhancing was skipped, because entity classes haven’t been changed since the last build
.
To disable this behavior and enhance all entities on each compilation, add the following configuration to build.gradle
:
jmix {
entitiesEnhancing {
skipUnmodifiedEntitiesEnhancing = false
}
}
Studio Improvements
Since Jmix Studio 2.2, the premium RAD features are available without an active subscription in small projects with up to 10 entities and roles. |
Code Snippets
New code snippets are available in Studio for BPM, Reports, Notifications and Email sending functionality if the corresponding add-ons are included in your project.
Adding Components Using Wizards
The Add Component action of View Designer now has two tabs:
-
From Palette tab shows the component palette as before;
-
Using Wizard tab contains wizards that help solving complex tasks related to UI. For example, the Edit entity attributes wizard creates a
formLayout
with fields for selected entity attributes and a data container with a proper fetch plan.The list of wizards is sensitive to the current view contents: for example, if the view already contains a
dataGrid
, the Add column to DataGrid wizard is available.
Link to UI Component Documentation
The inspector panel of the Jmix UI tool window now shows a link to the documentation on the selected UI component. See the question mark icon next to the component type.
The same link is available as the Jmix Documentation item in the component hierarchy context menu.
Test Scaffolding
Studio now shows the Tests item in the Jmix tool window. Double-click on this item opens the Project tree in the src/test/java
folder.
The New → Advanced → Integration Test and New → Advanced → UI Integration Test actions allow you to quickly create test classes for testing business logic and views.
Breaking Changes
Browser Tab Closing Prevention
The feature that prevents accidental browser tab closing introduced in Release 2.0 is now off by default. You can turn it on for a particular view using the setPreventBrowserTabClosing(true)
method or globally for the application using the following application property:
jmix.ui.view.prevent-browser-tab-closing = true
Circular Dependencies Between Spring Beans
Previously, circular dependencies between Spring beans were enabled by Jmix on the framework level.
Jmix 2.2 doesn’t have circular dependencies itself anymore and doesn’t enable them in application projects by default.
There is a chance that your project contains circular dependencies between its Spring beans, therefore the Studio migration procedure automatically adds the following property to the project:
spring.main.allow-circular-references = true
We recommend you to remove this property and try to start the application. If it fails to initialize, either refactor your beans to eliminate circular dependencies, or return the property.
See #287 for more information.
Handling Empty Conditions
Previously, a property condition evaluated to true if its parameter value was empty (null, empty string or empty collection).
Since Jmix 2.2, the null or empty parameters do not lead to skipping conditions. For example, consider the following code:
dataManager.load(User.class)
.condition(PropertyCondition.contains("email", null))
.list();
In Jmix 2.1 and earlier, it executes the following SQL:
SELECT ID, ACTIVE, EMAIL, <...> FROM USER_
In Jmix 2.2, by default it executes the following SQL and passes null
as a parameter:
SELECT ID, ACTIVE, EMAIL, <...> FROM USER_ WHERE EMAIL LIKE ?
As a result, in Jmix 2.1 the whole list of users is returned, while in Jmix 2.2 the result list is empty.
If you want to return the previous behavior, set the following application property:
jmix.core.skip-null-or-empty-conditions-by-default = true
The Studio migration procedure automatically adds this property to your project.
Alternatively, you can skip empty parameters for particular conditions:
dataManager.load(User.class)
.condition(PropertyCondition.contains("email", null).skipNullOrEmpty())
.list();
See #2490 for more information.
NoResultException
io.jmix.core.NoResultException
is now thrown instead of java.lang.IllegalStateException
if the one()
method of DataManager’s fluent loading API returns no results. See #2682.
Pessimistic Locking
The pessimistic locking feature has been extracted to the add-on.
The io.jmix.core.pessimisticlocking
package has been renamed to io.jmix.pessimisticlocking
.
Changed the following properties:
-
jmix.core.pessimistic-lock.use-default-quartz-configuration
→jmix.pslock.use-default-quartz-configuration
-
jmix.core.pessimistic-lock.expiration-cron
→jmix.pslock.expiration-cron
The Studio migration procedure automatically adds dependencies to your build.gradle
and changes the imports and property names.
See #1958 for more information.
Validation in File Upload Fields
The isInvalid()
method of fileUploadField and fileStorageUploadField does not trigger validation anymore. It only checks invalid state of the field. See #2821.
Security in Application Settings
The Application Settings add-on now doesn’t require to add security permissions to AppSettingsEntity
entity to work with settings through the AppSettings
bean.
If you want to return the previous behavior, set the following application property:
jmix.appsettings.check-permissions-for-app-settings-entity = true
The Studio migration procedure automatically adds this property to your project.
See #2710 for more information.
Security Views
The layout of the standard security views for resource and row-level roles has been changed for better usability, see #2519.
If you have extended these views, you may have to modify your code.
DetailView and DataContext Interfaces
The following methods have been added as part of the detail view save performance improvement:
-
DataContext.save(boolean reloadSaved)
-
DetailView.isReloadSaved()
-
DetailView.setReloadSaved(boolean reloadSaved)
You may need to modify your code if you directly implemented these interfaces.
Also, DataContext.PostSaveEvent.getSavedInstances()
method returns an empty collection if the entities were not reloaded. It can be checked using the new DataContext.PostSaveEvent.isEntitiesReloaded()
method.
DTO Entities in Standard Views
The framework now doesn’t make any difference between JPA and DTO entities when navigating to a detail view: it passes the entity ID in the route parameter. The detail view for DTO entity is supposed to get this ID and load the entity instance from some data storage using the load delegate. If the "new"
constant is passed instead of ID, the view creates a new instance.
If the whole entity instance is passed instead of ID (e.g. when opening in a dialog window), EntityStates.isNew()
is used to distinguish between Edit and Create mode. Consequently, it’s important to set the entity in the not-new state after loading it from a storage. For a DTO entity it can be done using the new EntityStates.setNew()
method, for JPA entity it’s done by the standard JPA data store implementation.
If the edited entity should not be reloaded from the data storage before setting to the data container, call setReloadEdited(false)
in the detail view constructor or the InitEvent
handler. This is the case for DTO entities existing purely in memory and not mapped directly to external data.
See #2788 for more information and recommendations and the External Data Sample project for example code.
Maps API
The following changes have been made in the Maps add-on:
-
io.jmix.mapsflowui.kit.component.model.style.text.Padding
has been moved toio.jmix.mapsflowui.kit.component.model
package. See #2822. -
The
addStyles()
method of theFeature
,PointFeature
,MarkerFeature
,LineStringFeature
,PolygonFeature
classes now returnsvoid
. UsewithStyles()
instead if you need the current instance of the feature. See #2807. -
In the
VectorLayer
class, theaddStyles()
method now returnsvoid
. UsewithStyles()
instead if you need the current instance of the layer. Renamed methods:isDeclutter()
→getDeclutter()
,isUpdateWhileAnimating()
→getUpdateWhileAnimating()
. See #2790. -
In the
ClusterSource
class, theaddPointStyles()
method now returnsvoid
. UsewithPointStyles()
instead if you need the current instance of the source. See #2790. -
In the
Layer
class, theisVisible()
method is renamed togetVisible()
. See #2790. -
The type of zoom properties in
VectorLayer
,TileLayer
,ImageLayer
andGeoMapView
has been changed fromInteger
toDouble
. See #2701.