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.

creating new project

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

select project template

On the next step, set a project name - planner, select its location and base package. Let’s set an optional project id. Studio will use it as a prefix for entity, table, and bean names.

select project name and id

Click Finish and wait for the empty project to load.

After the first launch, Jmix Studio offers you to apply a trial subscription to Jmix Studio Premium.

trial

Let’s apply a trial subscription. It is free for 28 days and gives us some useful optional designers.

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.

Diagram

For a starter, let’s create the Speaker entity. Do this using Jmix Tool Window. Click the + icon in the toolbar and select JPA Entity.

create new entity menu

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

set entity class

In the entity designer, create attributes according to the specification:

Name Type Mandatory Other constraints

firstName

String (255)

Yes

lastName

String (255)

email

String (255)

Yes

“Email” validator

In Jmix we use standard JPA entities, so you can create them using either a code editor or a visual designer:

entity designer empty

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

add new attribute

To add validation to the email attribute, select the attribute in the list. You will see the Validation section in the right part of the entity designer.

email validator select

Click 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.

email validator enabled dialog

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.

entity instance name

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, the 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 endDate 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 Speaker entity, many-to-one cardinality

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:

speaker reference attribute

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

talk 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 clear 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.

create calculated attribute end date

After creating the attribute, switch to the editor and add the calculation logic.

@Transient
@JmixProperty
@DependsOnProperties({"startDate", "duration"})
public LocalDateTime getEndDate() {
    return (startDate != null && duration != null) ? startDate.plusHours(duration) : null;
}

In the previous section, 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 the 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. Start a wizard by selecting Create screen in the Screens menu on the top of the entity designer.

run screen generator

You can also start screen generation wizard by selecting New → Screen in the context menu of the Backoffice UI node in the Jmix tool window.

context create screen

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

create screen dialog

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 consists of the SpeakerBrowse.java and speaker-browse.xml files and editor - SpeakerEdit.java and speaker-edit.xml accordingly.

You can find sources for these screens in the main/java and main/resources sections in the project’s source tree.

screens in 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="_base"/>
        <loader id="speakersDl">
            <query>
                <![CDATA[select e from planner_Speaker e]]>
            </query>
        </loader>
    </collection>
</data>

You can easily navigate between a screen controller, descriptor, and linked entities with Jmix Studio using buttons on the top of the window:

controller controls
layout controls
entity controls

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 we can define several fetch plans for every entity. 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 an 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.

talk browse fetch plan

At the next step, the necessary fields are already selected.

talk edit fetch plan

After screens are created, you can see screen preview by using buttons in the top right corner of the screen layout editor.

screen view switch buttons
  • Markup-only view(1).

  • Combined markup and preview(2).

  • Preview only(3).

  • Preview in a popup window(4).

The preview shows that all selected attributes are added to the screens.

talk edit screen layout

Database Creation

For this example, we will use an 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 Data Stores section of the Jmix tool window.

jmix project window

You can double-click Main Data Store to open database settings.

datastore 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 Main Data Store in Jmix tool window and select Generate Liquibase Changelog. Please note that you may see a message that some scripts have not been applied. This happens due to a system User entity that was created automatically. Please apply scripts before generating scripts for new entities.

generate diff script

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

liquibase scripts

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 Main Data Store in the Jmix tool window and select Update.

update database

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.

run configuration menu

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 at the bottom of the IDE in the Run window.

application run console

Open the URL in your 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 an invalid email for a speaker and see that the email validator works as expected.

speakers browser
talk browser

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 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 a default value for the talk duration when creating talk in the UI.

Handling Screen Events

Jmix Backoffice 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 GUI that allows you to initiate handler’s code generation from the component inspector.

To generate a default value for the talk duration property, we need to handle a talk creation event in the editor screen. To do that, you need to open the talk-edit.xml file and select the window component in the Component Hierarchy tool window in the top right corner in the Jmix Studio.

component hierarchy window

After that, you can see all possible handlers in the Component Inspector window in the left bottom corner of the IDE. If the tool window is collapsed, just expand it by pressing the corresponding button on the left IDE window border.

component inspector window

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 can fill the handler body with a simple assignment. Just get a newly created entity from the event object and set the 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 a tab control, put a calendar on it and provide functionality to edit and reschedule talks using this calendar like in the picture below:

application with calendar

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

component hierarchy wrap

Add one more tab page under the tabSheet by dragging the Tab component from the Component Palette.

tab sheet palette

Put a calendar control on it.

calendar on tab

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.

component id request

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

assign calendar tab header

Update the calendar - assign the talksDc data container.

assign container to calendar

Then assign the talksCalendar id 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.

calendar expand in 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 the talk’s startDate.

  • endDateProperty to the talk’s endDate.

  • captionProperty to the talk’s topic.

  • descriptionProperty to the talk’s description.

calendar propeties

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

calendar working hours

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

navigation buttons visible xml

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 file, 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 then move to the controller.

generate calendar event handler

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 Backoffice 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:

screen editor toolbar

And in the dialog window, select the service:

inject screen api dialog

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. The code below just illustrates all the steps:

@Subscribe("talksCalendar")
public void onTalksCalendarCalendarEventClick(Calendar.CalendarEventClickEvent<LocalDateTime> event) {
    screenBuilders.editor(Talk.class, this) (1)
            .editEntity((Talk)event.getEntity()) (2)
            .withOpenMode(OpenMode.DIALOG) (3)
            .withScreenClass(TalkEdit.class) (4)
            .withAfterCloseListener(afterCloseEvent -> { (5)
                if (afterCloseEvent.closedWith(StandardOutcome.COMMIT)) {
                    getScreenData().loadAll();
                }
            }).show(); (6)
}
1 Creates an editor for the Talk entity using this instance of the browser screen as a parent.
2 Specifies the entity instance that will be edited by extracting it from the UI event.
3 Defines editor’s open mode. It will be a dialog for our case.
4 Specifies the exact editor’s screen class. In general, there might be more than one screen that can be used to edit the talk.
5 Reloads data in the screen if the editor was closed using the Save button.
6 Shows the editor.

Now, if you restart the application and click on an event, you will see the talk editor.

talk editor big

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.

dialog mode auto

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

talk editor auto

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 Spring bean for the talks rescheduling that will ensure that one speaker doesn’t have more than two talks in one day.

Use a toolbar in the Jmix tool window to open commonly used actions. Select Spring Bean.

create new class

Enter the package name - service and the class name - TalksScheduleService.

create new package

Studio will generate an empty class.

empty class

Let’s create the rescheduleTalk method. You can see its implementation below:

@Component("planner_TaskScheduleService")
public class TalksScheduleService {

    @Autowired
    private DataManager dataManager;

    public Talk rescheduleTalk(Talk talk, LocalDateTime newStartDate) { (1)
        LocalDateTime dayStart = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(8); (2)
        LocalDateTime dayEnd = newStartDate.truncatedTo(ChronoUnit.DAYS).withHour(19); (3)

        Long talksSameTime = dataManager.loadValue("select count(t) " + (4)
                "from planner_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) { (5)
            return talk; (6)
        }
        talk.setStartDate(newStartDate); (7)
        return dataManager.save(talk); (8)
    }

}
1 The rescheduleTalk method accepts a talk that should be rescheduled and new talk start time.
2 Calculates new start time of the day when the session is planned.
3 Calculates new end time of the day when the session is planned.
4 We 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. To inject DataManager into the service, use the Inject button on the top of the code editor, and then select DataManager in the pop-up screen.
5 Checks the query result.
6 Returns the original talk instance if a speaker has two or more talks for the day.
7 Updates the talk with a new start date if a speaker has less than two talks for the day.
8 Returns the updated talk.

The service is ready, 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 the method stub and move to the controller.

generate event handler

You need to inject TalksScheduleService to the screen before implementing the event handler. Here is the implementation of the method:

@Subscribe("talksCalendar")
public void onTalksCalendarCalendarEventMove(Calendar.CalendarEventMoveEvent<LocalDateTime> event) {
    talksScheduleService.rescheduleTalk((Talk)event.getEntity(), event.getNewStart()); (1)
    getScreenData().loadAll(); (2)
}
1 We extract the talk entity from the calendar event and pass it to the service to reschedule this talk.
2 After that, we just refresh the screen data programmatically.

To have the service redeployed, we need to restart the application. After restarting, we can open the calendar. We have drag-and-drop rescheduling functionality for the calendar. You can test it by adding an extra talk and trying to reschedule it.

move talks

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 open message pack using Jmix tool window. Expand the Backoffice UI node and double-click Message Bandle.

messages file in trees

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.

new branding labels

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.