Documentation

Documentation versions (currently viewing)

Loading & Saving Business Objects

Loading business objects and then saving them.

Form state is loaded from business objects, and can be saved normally after validation. Once bindings are set up, you’re ready to fill the bound UI components with data from your business objects. Changes can be written automatically or manually to business objects.

Reading & Writing Automatically

Writing automatically to business objects when the user makes changes in the UI is usually the most convenient option. You can bind the values directly to an instance by allowing Binder to save automatically values from the fields.

In the example here, field values are saved automatically:

Binder<Person> binder = new Binder<>();

// Field binding configuration omitted.
// It should be done here.

Person person = new Person("John Doe", 1957);

// Loads the values from the person instance.
// Sets person to be updated when any bound field
// is updated.
binder.setBean(person);

Button saveButton = new Button("Save", event -> {
    if (binder.validate().isOk()) {
        // Person is always up-to-date as long as
        // there are no validation errors.

        MyBackend.updatePersonInDatabase(person);
    }
});

The validate() call ensures that bean-level validators are checked when saving automatically.

Warning
When you use the setBean() method, the business object instance updates whenever the user changes the value of a bound field. If another part of the application simultaneously uses the same instance, that part could display changes before the user saves. You can prevent this, though, by using a copy of the edited object, or by manually updating the object only when the user saves.

Reading Manually

You can use the readBean() method to read manually values from a business object instance into the UI components.

This example is using the readBean method:

Person person = new Person("John Doe", 1957);

binder.readBean(person);

The example above assumes that binder has been configured with a TextField bound to the name property. The value "John Doe" displays in the field.

Validating & Writing Manually

To prevent displaying multiple errors to the user, validation errors only display after the user has edited each field and submitted (i.e., loaded) the form.

You can explicitly validate the form or try to save the values to a business object, even if the user hasn’t edited a field.

In this example, it’s explicitly validating a form:

// This makes all current validation errors visible.
BinderValidationStatus<Person> status =
        binder.validate();

if (status.hasErrors()) {
   notifyValidationErrors(status.getValidationErrors());
}

Writing the field values to a business object fails if any of the bound fields contain an invalid value. You can handle invalid values in many different ways. The following are some examples:

try {
    binder.writeBean(person);
    MyBackend.updatePersonInDatabase(person);
} catch (ValidationException e) {
    notifyValidationErrors(e.getValidationErrors());
}
boolean saved = binder.writeBeanIfValid(person);
if (saved) {
    MyBackend.updatePersonInDatabase(person);
} else {
    notifyValidationErrors(binder.validate()
            .getValidationErrors());
}
try {
    // Writes values from bindings that have changed, as tracked by Binder.
    binder.writeChangedBindingsToBean(person);

    // Alternatively, this writes values of given set of bindings to the bean.
    Collection<Binding<Person, ?>> bindingsToWrite = ...; // define a set of bindings
    binder.writeBean(person, bindingsToWrite);

    MyBackend.updatePersonInDatabase(person);
} catch (ValidationException e) {
    notifyValidationErrors(e.getValidationErrors());
}
binder.withValidator(
       p -> p.getYearOfMarriage() > p.getYearOfBirth(),
       "Marriage year must be bigger than birth year.");

The withValidator(Validator) method runs on the bound bean after the values of the bound fields have been updated.

Bean-level validators also run as part of writeBean(Object), writeBeanIfValid(Object), and validate(Object) — if the content passes all field-level validators.

Note
For bean-level validators, the bean must be updated before the validator runs. If a bean-level validator fails in writeBean(Object) or writeBeanIfValid(Object), the bean reverts to the state it was in before it returns from the method. Remember to check your getters/setters to ensure there are no unwanted side effects.

Writing as a Draft

In addition to other means of writing field values to a business object, there’s also a way to write the bean as a draft. This means that it’s not required for all field validations to pass, and bean-level validation isn’t run at all.

// This will write all values which pass conversion and field-level validation to person bean.
binder.writeBeanAsDraft(person);

// This will write all values which pass conversion to person bean, ignoring field-level validation.
binder.writeBeanAsDraft(person, true);

Tracking Binding Status

Binder keeps track of which bindings have been updated by the user and which bindings are in an invalid state. It fires an event when there are status changes. You can use this event to enable and disable the form buttons, depending on the current status of the form.

This example is enabling the Save and Reset buttons when changes are detected:

binder.addStatusChangeListener(event -> {
    boolean isValid = event.getBinder().isValid();
    boolean hasChanges = event.getBinder().hasChanges();

    saveButton.setEnabled(hasChanges && isValid);
    resetButton.setEnabled(hasChanges);
});

33EBA0BC-10B8-4DB4-922C-71AA8B0A446C