Architecture

Data Binding with PMOs

With linkki, UI components are defined in so called Presentation Model Objects (PMOs). The dynamic aspects of the UI are defined in methods, while the UI component itself is defined in annotations. This enables a declarative definition of UIs.

The PMO isn’t required to hold all data itself. It can delegate to domain model objects (see Data on Multiple Layers) to directly make use of existing domain logic.

linkki PMO and PMO properties

In linkki, PMOs are Plain Old Java Objects (POJOs), in which data for individual UI layouts are structured.

Of importance for the data binding are the so called properties of a PMO. A PMO has a PMO property named "something" if and only if that class has a method getSomething() (isSomething() for boolean). If the value of this property is to be modifiable, the method setSomething must exist additionally. The value of the property may be stored in a field something but that is not required. Neither does a PMO have to be a JavaBean with a zero-argument constructor.

See the following example class:

public class ExamplePmo {

    private String surname = "";

    private String salutation = "";

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getSalutation() {
        return salutation;
    }

    public void setSalutation(String salutation) {
        this.salutation = salutation;
    }

    public String getNameForUI() {
        return String.join(" ", salutation, surname);
    }
}

This class has two properties: "salutation" and "nameForUI". The property "nameForUI" shows, that for a PMO property there doesn’t necessarily have to exist a corresponding field. Also, "surname" is no property even though there is a field and a matching setter method, because the required method String getSurname() is missing.

Defining UI components in a PMO

UI components are defined by using annotations. Each PMO property can be defined as UI component by using an UI element annotation. In addition the PMO itself can be defined as a layout.

Example: annotated PMO
@UISection(caption = "Partner")
public class PartnerSectionPmo {

    private Partner partner;

    public PartnerSectionPmo(Partner partner) {
        this.partner = partner;
    }

    @UITextField(position = 1, label = "Name", width = "20em")
    public String getName() {
        return partner.getName();
    }

    public void setName(String newName) {
        partner.setName(newName);
    }

    @UIDateField(position = 2, label = "Date of Birth")
    public LocalDate getDateOfBirth() {
        return partner.getDateOfBirth();
    }

    public void setDateOfBirth(LocalDate newDateOfBirth) {
        partner.setDateOfBirth(newDateOfBirth);
    }
}

Additional interfaces for PMOs

There are some optional interfaces that PMO classes may implement:

  • org.linkki.core.pmo.PresentationModelObject offers a method for the creation of a button PMO. This button is displayed in the section header if the PMO is annotated with @UISection.

  • org.linkki.core.pmo.ButtonPmo is a PMO for buttons, see Buttons

  • org.linkki.core.defaults.columnbased.pmo.ContainerPmo is a PMO for tables, of which each row is represented by regular PMOs. See Container Components