Quick Start
Preface
In this quick start, we will scratch the surface of Jmix and develop a very simple, but fully functional planner application that will help with talk scheduling for a conference. It will show some necessary things for creating any web application: how to design a data model, how to manipulate data, how to create business logic and, finally, how to create a user interface. In fact, this tutorial will be just enough for you to start your own Jmix application, so let’s get started. In this tutorial, we will use Jmix Studio, so please install it before you begin.
Creating Empty Project
Let’s create an empty Jmix project using the corresponding Intellij IDEA menu. First, select Jmix version. We will use Java 11 as the default JDK.

After that, click 'Next' button and select a project template.

On the next step, set project name - "planner", select its location, base package.

Default project id - "planner" is too long, it should be 6 characters maximum.

Let’s shorten it by clicking on "Shorten" button near the "Project id" field.

Click on the "Finish" button and wait for the empty project to load.
Creating Data Model
The first task is creating entities. The business domain model has only two classes: Speaker and Talk. The relation is one-to-many. One speaker can conduct many talks.

For a starter, let’s create the Speaker
entity. To do this, you just need to expand src/main/java
folder, right-click on any package in your source code and select New → JPA Entity…
:

Enter entity’s class - "Speaker". For this sample application, we do not need to change other entity parameters.

In the entity designer, create attributes according to the specification:
Name | Type | Mandatory | Other constraints |
---|---|---|---|
firstName |
String (255) |
Yes |
|
lastName |
String (255) |
||
String (1024) |
Yes |
“Email” validator |
In Jmix we use standard JPA entities, so you can create them using either code editor or visual designer:

In the visual designer, just click on "+" icon to add attributes to the entity, Jmix Studio will generate class members for you.

To add validation to the email attribute, create this attribute and then select Email validator in the Validation section in right part of the entity designer.

Click on the not set
label to invoke the validator editor and enable the validator. You can specify a custom error message or a regexp for validation if needed.

To display an entity in a readable format, you can select one of the fields or use a method annotated with @InstanceName
. For now, we will use lastName
field for this. We can choose the field in the entity designer.

If we open the Text tab on the bottom of the entity designer, we can see just a JPA-annotated java class. The generated code can be updated if needed, designer will be updated accordingly when you switch to the Designer tab.
Let’s move further and create the Talk
entity and link it to the Speaker
class. Fields specification table follows. Talk’s End time
field will be a calculated field, being the start date and time plus duration, we will create it later.
Name | Type | Mandatory |
---|---|---|
topic |
String (255) |
Yes |
startDate |
LocalDateTime |
Yes |
speaker |
Association to the |
Yes |
duration |
Integer |
Yes |
description |
String (Unlimited) |
Look at the mandatory reference to the speaker attribute. The relation is many-to-one, so, we’ll define an association field called "speaker" that references the Speaker
class. In the end, the field definition should look like this:

For the Talk
entity let’s choose the topic
attribute as the instance name

We have almost created the entity model for our application.
Creating Calculated Attribute
Now, we need to create an auto calculated attribute for the talk’s end date and time. Create a new attribute endDate
of LocalDateTime
type and mark it as Transient. We do not need to generate a field for this attribute, so uncheck the Create field checkbox.
For the calculated attribute, we need to specify the fields to be loaded. In our case, these are startDate
and duration
. Click on the ✎ icon in the Related attributes field to invoke the editor.

After creating the attribute, switch to the editor and add the calculation logic.
@JmixProperty
@DependsOnProperties({"startDate", "duration"})
public LocalDateTime getEndDate() {
return (startDate != null && duration != null) ? startDate.plusHours(duration) : null;
}
In the previous section - "Creating application’s data model", for the Speaker
entity we have defined lastName
as an entity’s instance display name. Now we can define a method that will use a speaker’s full name to display them in the UI.
To do this, we need to create a new method - getFullName()
in the Speaker
class and make its return type String
. Then we need to move (cut and paste) annotation @InstanceName
from lastName
field to this method and add @DependsOnProperties
annotation to use firstName
and lastName
fields in the method. Then all we need to do is to generate full speaker’s name in the method body.
@InstanceName
@DependsOnProperties({"firstName", "lastName"})
public String getFullName() {
return String.format("%s %s", firstName, lastName);
}
That’s it. Our domain model has been created with calculated fields.
Generating CRUD Screens
Jmix Studio contains a UI screen generation wizard that helps us to create basic, but useful UI screens:
-
Browser - to show the list of entities in a grid
-
Editor - to edit one entity instance using a form-like user interface
Screens for "Speaker" Entity
First, we will create screens to work with speakers. Since this entity is pretty simple, we will use the default parameters for the screen creation. Start a wizard by clicking on Create Screen menu item in Screens menu on the top of the entity designer.

You can also start screen generation wizard by right-clicking on an entity in Jmix Project tree and selecting New → Screen from the context menu.

For the Speaker
entity, we will create default browser and editor. Select Entity browser and editor screens on the Screen Templates tab in the wizard and click Next. Since this entity is pretty simple, we can accept the default parameters for the screen creation.

Just click Next on all other screen creation steps and two screens will be created.
Each screen consists of two parts: a controller, written in java, which is responsible for internal screen logic and events handling, and an XML layout that defines the screen appearance. In our case, the browser will consist of files SpeakerBrowse.java
and speaker-browse.xml
and editor - SpeakerEdit.java
and speaker-edit.xml
accordingly.
You can find sources for these screens in main/java
and main/resources
sections in the project’s source tree.

Please note the data
section in the XML screen descriptors - it defines how the data is fetched from the database.
<data readOnly="true">
<collection id="speakersDc"
class="com.company.planner.entity.Speaker">
<fetchPlan extends="_local"/>
<loader id="speakersDl">
<query>
<![CDATA[select e from plnnr_Speaker e]]>
</query>
</loader>
</collection>
</data>
You can easily navigate between screen controller, descriptor and linked entities with Jmix Studio using buttons on the top of the window:



Screens for "Talk" Entity
Run the screen generation wizard for the Talk
entity, select Entity browser and editor screens and stop at the Entity browser fetch plan step.
In Jmix for every entity we can define several fetch plans. They specify which fields will be fetched from the database. You can define fetch plans in a separate file to use them in the different modules of your application, or create inline fetch plan while creating a screen.
Let’s create an inline fetch plan. In addition to selected properties, mark end date and speaker reference.

You can see that all selected attributes are added to the screens.

To see screen preview, you can use buttons in the top right corner of the screen layout editor:

-
Markup-only view
-
Combined markup and preview
-
Preview only
-
Preview in a popup window
Database Creation
For this example, we will use in-memory database - HSQLDB, so the database itself will be created automatically. If you want to use a different RDBMS like MySQL or PostgreSQL, please create an empty database according to your RDBMS documentation.
You can find database settings in the Jmix project window located in the bottom left corner of the Jmix Studio window.

You can double-click on the Main Data Store node to see database settings.

If you would prefer using a different RDBMS for this quick start, make sure that URL, username and password match the connection parameters for the database that you had created manually.
Jmix uses Liquibase for database creation and updates, so we need to generate Liquibase scripts to create the database for the conference planner. Jmix Studio analyzes the existing database schema and generates scripts to synchronize the existing JPA data model and database tables.
To start Liquibase scripts generation, right-click on the Main Data Store node in Jmix project window and select Generate Diff Changelog. Please note that you may see a message about that some scripts have not been applied. This happens due to a system User
entity that was created automatically. Please apply scripts before generating diff scripts for new entities.

You can review the generated scripts in the project sources in src/main/resources/<project package>/liquibase
folder.

You can add custom scripts if you want to add some specific things like additional indexes or insert statements for the initial data. Please refer to the Database Migration section for more information.
After scripts are created, you can apply them to the database. Right-click on the Main Data Store node in the Jmix project window and select Update

The database has been created.
Running Application in Development Mode
To run the application, you can use Run Configuration tool on the top of the IDE window.

After some time you can access the application using the browser. By default, the URL will be http://localhost:8080/ .
You can see the application log file in the bottom of the IDE in the Run window.

Open the URL in your web browser and log into the application using “admin” as a username. The password is “admin” by default. You can find screens for entities manipulation under Application menu.
Then let’s add some data to the database: a couple of speakers and two talks scheduled for the rest of the week. You can try to enter invalid email for a speaker and see that email validator works as expected.


Generated screens are good for basic operations, but in the real world, UI is usually more complex.
Processing Events
Jmix provides an API to handle various events happening in the application - starting from entities persistence process to mouse clicks on a buttons.
With Jmix Studio, you can generate empty event handlers and then add your business logic into the generated code. For the conference planning application, we need to set default value for the talk duration when creating talk in the UI
Handling Screen Events
Jmix’s Generic UI allows developers to handle various events that are generated by screens and components. All you need to do is to create a method with a proper signature and annotation for a particular event. Jmix Studio provides a GUI that allows you to initiate handler’s code generation from the component inspector.
To generate default value for the talk duration property we need to handle talk creation event in the editor screen. To do that, you need to open the talk-edit.xml
file and select window
component in the Component Hierarchy tool window in the top right corner in the Jmix Studio.

After that, you should be able to see all possible handlers in th Component Inspector window in the left bottom corner of the IDE. The tool window may be collapsed, just expand it by pressing the corresponding button on the left IDE window border.

We need to process InitEntityEvent
event, just double-click on the corresponding <empty>
section in the Component Inspector. You will be redirected to the screen controller, where you should be able to fill the handler body with a simple assignment. Just get a newly created entity from the event object and set duration to one hour.
@Subscribe
public void onInitEntity(InitEntityEvent<Talk> event) {
event.getEntity().setDuration(1);
}
Customizing User Interface
Let’s add a calendar view to browse talks in addition to the grid view. For the browser screen, we’ll add tab control, put a calendar on it and provide a functionality to edit and reschedule talks using this calendar like in the picture below:

Open talk-browse.xml file in designer and wrap the sessions table into tab sheet by right-click on the talksTable
component in the Component Hierarchy window.

Add one more tab page under the TabSheet by dragging-and-drop Tab component from the Component Palette.

Put a calendar control on it.

Select the TabSheet element in the Component Hierarchy window and select expanded in the Component Inspector. Studio asks for an ID. In Jmix, we need IDs to reference a screen element in the code. Set talksTabSheet
id for the component.

Assign ids calendarTab
and tableTab
for the tabs. Then set captions Talks calendar and Talks table for these tabs accordingly. You can create internationalized messages by clicking on 🌐 icon near the caption property.

Update the calendar - assign the talksDc
data container.

Then assign id talksCalendar
to the calendar component and set this id as the expand property value for the calendarTab
component. After this the calendar should be expanded to all free space on its tab.

In Jmix Backoffice UI, components can be bound to entities and their properties.
Let’s bind the calendar to the data collection fetched in the screen to the talksDc
container. Use the search field to find properties and bind:
-
startDateProperty to a talk’s start Date
-
endDateProperty to a talk’s end Date
-
captionProperty to a talk’s topic
-
And descriptionProperty to a talk’s description

Let’s make the calendar to show only working hours.

In addition to the visual designer, you can use the XML markup editor. Let’s add navigation buttons.

Restart the application and reopen Talk browser screen in the application. Now you can see talks are displayed on the calendar.
Using Screen API
Let’s handle a click on a calendar’s entry and invoke the talk editor. For screen manipulations, Jmix provides a screen builder API that we will use.
In the talk-browse.xml
select talksCalendar
and go to the Handlers tab in the Component Inspector window. Select CalendarEventClickEvent handler and click on the ▶ icon to generate the code and move to the controller.

The empty method will be generated for you.
@Subscribe("talksCalendar")
public void onTalksCalendarCalendarEventClick(Calendar.CalendarEventClickEvent<LocalDateTime> event) {
}
We need to invoke the editor screen to change the talk’s properties. Jmix framework provides a set of screen API services to simplify work with the Generic UI screens.
To get access to screen API, specifically to the ScreenBuilders
service, you need to inject it into the screen.
To do this, click on the Inject button in the screen’s controller source code editor toolbar:

And in the dialog window, select the service:

Jmix’s screen builder API allows us to do invoke the editor pretty easy by adding several method calls to a builder step by step:
-
Create an editor for the
Talk
entity usingthis
instance of the browser screen as a parent -
Then we specify the entity instance that will be edited by extracting it from the UI event
-
After that - define editor’s open mode. It will be dialog for our case
-
Then we specify exact editor’s screen class. In general, there might be more that one screen that can be used to edit the talk
-
Then we need to reload data in the screen if the editor was closed using the Save button
-
Finally, we show the editor
The code below just illustrates all the steps.
@Subscribe("talksCalendar")
public void onTalksCalendarCalendarEventClick(Calendar.CalendarEventClickEvent<LocalDateTime> event) {
screenBuilders.editor(Talk.class, this)
.editEntity((Talk)event.getEntity())
.withOpenMode(OpenMode.DIALOG)
.withScreenClass(TalkEdit.class)
.withAfterCloseListener(afterCloseEvent -> {
if (afterCloseEvent.closedWith(StandardOutcome.COMMIT)) {
getScreenData().loadAll();
}
}).show();
}
Now if you restart the application and click on an event, you will see the talk editor.

The editor doesn’t look nice, so we need to adjust its width and height. In the IDE, open the screen’s XML descriptor - talk-edit.xml
, select dialogMode component in the Component Hierarchy window and set width and height properties to auto
in the Component Inspector.

Restart the application, open the Talk browser and click on a talk on the calendar again - you should see the editor dialog displayed correctly.

Now the editor looks nicer.
Adding Business Logic
Now we will use Jmix Studio to create a service that implements business logic and use this service in a screen. It will be a service for the talks rescheduling that will ensure that one speaker doesn’t have more than two talks in one day.
Right-click on the root project package in the source project tree and select New →Package.

Create the package com.company.planner.service
.

Right-click on the created package and select New →Java Class.

Create the class TalksScheduleService
.

public class TalksScheduleService {
}
Mark this class with the @Service
annotation and create a method rescheduleTalk
that will accept a talk that should be rescheduled and new talk start time like in the snippet below. During the further service implementation you may need to import some classes.
@Service
public class TalksScheduleService {
public Talk rescheduleTalk(Talk talk, LocalDateTime newStartDate){
return null;
}
}
First, let’s calculate the start and end time of the day when the session is planned.
@Service
public class TalksScheduleService {
public Talk rescheduleTalk(Talk talk, LocalDateTime newStartDate){
LocalDateTime dayStart = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(8);
LocalDateTime dayEnd = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(19);
return null;
}
}
For the service, we will use Jmix API for data access - DataManager
class. With this class we create a JPQL query to check if there are any talks scheduled for the speaker in a defined time span and add parameter values to it. Then we check the query result and, depending on the result, we update the talk with a new start date or just return the original talk instance.
Inject the DataManager into the service into the class body. You can use Inject button on the top left corner in the code editor.

Select DataManager in the popup screen.

The method implementation is on the snippet below:
@Service
public class TalksScheduleService {
@Autowired
private DataManager dataManager;
public Talk rescheduleTalk(Talk talk, LocalDateTime newStartDate){
LocalDateTime dayStart = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(8);
LocalDateTime dayEnd = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(19);
Long talksSameTime = dataManager.loadValue("select count(t) from plnnr_Talk t where " +
"(t.startDate between :dayStart and :dayEnd) " +
"and t.speaker = :speaker " +
"and t.id <> :talkId", Long.class)
.parameter("dayStart", dayStart)
.parameter("dayEnd", dayEnd)
.parameter("speaker", talk.getSpeaker())
.parameter("talkId", talk.getId())
.one();
if (talksSameTime >= 2) {
return talk;
}
talk.setStartDate(newStartDate);
return dataManager.save(talk);
}
}
The service is ready, now let’s add it to the talks browser screen. It will be invoked for the drag-and-drop event in the calendar.
In the talk-browse.xml
select talksCalendar
and go to the Handlers tab in the Component Inspector window. Select CalendarEventMoveEvent and click the ▶ icon to generate method stub and move to the controller. We did similar work before in the "Using screen API" chapter.
In the method that is subscribed to the drag-and-drop event, we add some code to extract the talk entity from the calendar event and pass it to the service to reschedule this talk. After that, we just refresh the screen data programmatically. Please inject TalksScheduleService
to the screen before implementing the event handler.
@Subscribe("talksCalendar")
public void onTalksCalendarCalendarEventMove(Calendar.CalendarEventMoveEvent<LocalDateTime> event) {
talksScheduleService.rescheduleTalk((Talk)event.getEntity(), event.getNewStart());
getScreenData().loadAll();
}
To have the new service redeployed, we need to restart the application. After restarting we can open the calendar - and voilà! We have drag-and-drop rescheduling functionality for the calendar! You can test it by adding an extra talk and trying to reschedule it.
Adding Branding
In Jmix, you can update resource files and override the standard text. Let’s update the text according to the application business domain - conference planning.
You can find message pack under src/main/resources/<project root package>
in the source tree ot under Generic UI node in the Jmix project tree.

It is a standard java .properties
file, so you can edit it freely, adding new message keys and updating existing ones. Update messages to reflect the purpose of the application. The example is below:
com.company.planner/menu.application=Talks and Speakers
com.company.planner.screen.main/application.caption = Conference Planner
com.company.planner.screen.main/application.logoLabel = Conference Planner
Restart the application to see the changes in the main menu.

Conclusion
Jmix provides a lot of useful APIs to help you with creating business applications quickly. This quickstart shows only the basics of the Jmix framework and Jmix Studio. You can find more examples and tutorials on our website: jmix.io.