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 'Next' button and select a project template.

select project template

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

select project name and id

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

project id too long

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

select project name short id

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.

er speaker talk

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…​:

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 (1024)

Yes

“Email” validator

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

entity designer empty

In the visual designer, just click on "+" 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, create this attribute and then select Email validator in the Validation section in right part of the entity designer.

email validator select

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.

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

create calculated attribute end date

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.

run screen generator

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.

context create screen

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.

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

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="_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:

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

talk screen fetch plan

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

talk edit screen layout

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

screen view switch buttons
  • 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.

jmix project window

You can double-click on the Main Data Store node to see 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 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.

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 on the Main Data Store node in the Jmix project 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 in the bottom of the IDE in the Run window.

application run console

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.

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

component hierarchy window

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.

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

application with calendar

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.

component hierarchy wrap

Add one more tab page under the TabSheet by dragging-and-drop 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 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.

assign calendar tab header

Update the calendar - assign the talksDc data container.

assign container to calendar

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.

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

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

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

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:

  • Create an editor for the Talk entity using this 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.

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 a talk on the calendar again - you should 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 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 new package

Create the package com.company.planner.service.

name new package

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

create new class

Create the class TalksScheduleService.

name new class
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.

inject button

Select DataManager in the popup screen.

inject service dialog

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.

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.