Documentation

Documentation versions (currently viewingVaadin 24)

Loading & Saving Business Objects

How to load business objects and save to them.

Form state is loaded from business objects, and can be saved normally after validation. Once your 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 to business objects automatically 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 automatically save values from the fields.

Example: Automatically saving field values.

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 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 manually read values from a business object instance into the UI components.

Example: Using the readBean method.

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

binder.readBean(person);
  • This example assumes that binder has been configured with a TextField bound to the name property.

  • The value "John Doe" displays in the field.

Validating and Writing Manually

To prevent displaying multiple errors to the user, validation errors only display after the user has edited each field and submitted (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.

Example: 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 deal with invalid values in many different ways:

Example: Handling a checked exception.

try {
    binder.writeBean(person);
    MyBackend.updatePersonInDatabase(person);
} catch (ValidationException e) {
    notifyValidationErrors(e.getValidationErrors());
}

Example: Checking a return value.

boolean saved = binder.writeBeanIfValid(person);
if (saved) {
    MyBackend.updatePersonInDatabase(person);
} else {
    notifyValidationErrors(binder.validate()
            .getValidationErrors());
}

Example: Adding bean-level validators.

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 appropriately, depending on the current status of the form.

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