> Markdown version of [Binding Beans to Forms](https://vaadin.com/docs/next/flow/binding-data/components-binder-beans). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Binding Beans to Forms

Beans are the standard Java model for business objects. This article describes how they are bound to forms. Business objects are typically implemented as JavaBeans in an application. `Binder` supports binding the properties of a business object to UI components in forms.

## <a id="manual-data-binding"></a>Manual Data Binding

You can use reflection based on bean property names to bind values. This reduces the amount of code needed when binding to fields in the bean.

To use reflection, create a `Binder` by providing the bean class, for example `new Binder<>(Person.class);`. By default, `Binder` inspects top level properties when it is instantiated. However, it can detect nested properties lazily when they’re bound to a view field.

To eagerly inspect nested properties, you can use the `Binder(Class<BEAN> beanType, boolean scanNestedDefinitions);` constructor, passing `true` as the value of `scanNestedDefinitions` parameter.

For example, to bind using reflection based on bean property names, you would do something like this:

```java
Binder<Person> binder = new Binder<>(Person.class);

// Bind based on property name
binder.bind(nameField, "name");
// Bind based on sub property path
binder.bind(streetAddressField, "address.street");
// Bind using forField for additional configuration
binder.forField(yearOfBirthField)
    .withConverter(
        new StringToIntegerConverter(
                "Enter a number"))
    .bind("yearOfBirth");
```

> **Note:** Be cautious when using strings to identify properties. A typo in the string, or a subsequent change to the setter and getter method names, results in a runtime exception.

## <a id="binding-nested-properties"></a>Binding Nested Properties

Binding nested properties is possible if the bean provides all of the `getters` necessary to reach the leaf property. The nested property should be expressed in the bean path syntax. For example, to bind the `street` property of `Address` class, through the `Person.address` field, you should:

- Have a `getStreet()` method in the `Address` class — provide also the `setStreet(String street)` method, if the property is writable;

- Have a `getAddress()` method in `Person` class — the getter should never return `null`, otherwise the nested binding will fail; and

- Bind the field using its bean path `address.street`, for example `binder.bind(streetAddressField, "address.street")`.

## <a id="automatic-data-binding"></a>Automatic Data Binding

The `bindInstanceFields()` method facilitates automatic data binding. UI fields are typically defined as members of a UI Java class. This allows you to access the fields using the different methods made available by the class.

In this scenario, binding the fields is also simple because when you pass the object to the UI class, the `bindInstanceFields()` method matches the fields of the object to the properties of the related business object based on their names.

For example, you could use the `bindInstanceFields()` method to bind all fields in a UI class like so:

```java
public class MyForm extends VerticalLayout {
    private TextField firstName =
            new TextField("First name");
    private TextField lastName =
            new TextField("Last name");
    private ComboBox<Gender> gender =
            new ComboBox<>("Gender");

    public MyForm() {
        Binder<Person> binder =
                new Binder<>(Person.class);
        binder.bindInstanceFields(this);
    }
}
```

This binds the `firstName` text field to the `firstName` property in the item, `lastName` text field to the `lastName` property, and the `gender` combo box to the `gender` property.

Without this method, it would be necessary to bind each field separately. Below is an example of this in which each field is bound separately:

```java
binder.forField(firstName)
    .bind(Person::getFirstName, Person::setFirstName);
binder.forField(lastName)
    .bind(Person::getLastName, Person::setLastName);
binder.forField(gender)
    .bind(Person::getGender, Person::setGender);
```

> **Tip:** Prefer explicit `forField().bind()` binding with getter and setter method references for anything beyond the simplest forms. It’s more readable, is checked at compile time, and doesn’t rely on field and property names matching. Automatic `bindInstanceFields()` binding is convenient for simple forms, but its reliance on naming conventions and its use of `@PropertyId` and `forMemberField()` to handle mismatches make it harder to maintain as a form grows. Binding by string property name is best reserved for record FDOs, whose component accessors can’t be referenced as method references.

### <a id="specifying-property-names"></a>Specifying Property Names

The `bindInstanceFields()` method processes all Java member fields with a type that implements `HasValue` (such as, `TextField`) that can be mapped to a property name.

If the field name doesn’t match the corresponding property name in the business object, you can use the `@PropertyId` annotation to specify the property name.

The `@PropertyId` annotation is mandatory if the field should be bound to a nested property. For example, using the `@PropertyId` annotation to specify the "sex" property for the `gender` field would look like this:

```java
@PropertyId("sex")
private ComboBox<Gender> gender = new ComboBox<>("Gender");

@PropertyId("address.street")
private TextField streetAddressField = new TextField("Street");
```

### <a id="configuring-converters-validators"></a>Configuring Converters & Validators

When using the automatic `bindInstanceFields()` method to bind fields, all converters and validators must be configured beforehand using a special `forMemberField()` configurator. This works similarly to the `forField()` method, but it requires no explicit call to a bind method. If the `bindInstanceFields()` method finds incompatible property-field pairs, it throws an `IllegalStateException`.

Alternatively, you can bind properties that need validators manually and then bind all remaining fields using the `bindInstanceFields()` method. This method skips the properties that have already been bound manually.

You can manually specify `StringToIntegerConverter`, for example, before calling the `bindInstanceFields()` method like so:

```java
TextField yearOfBirthField =
        new TextField("Year of birth");

binder.forField(yearOfBirthField)
  .withConverter(
    new StringToIntegerConverter("Must enter a number"))
  .bind(Person::getYearOfBirth, Person::setYearOfBirth);

binder.bindInstanceFields(this);
```

If you use Java Specification Requests (JSR) 303 validators, you should use `BeanValidationBinder`. It picks validators automatically when using `bindInstanceFields()`.

### <a id="automatically-applied-converters"></a>Automatically Applied Converters

The `bindInstanceFields()` method can simplify `Binder` configuration by automatically applying out-of-the-box converters from the `com.vaadin.flow.data.converter` package for known types. An automatic choice is made only for fields that aren’t manually configured using `forField()` or `forMemberField()`.

Converter instances are created using the `ConverterFactory` provided by the `Binder.getConverterFactory()` method. If a suitable converter can’t be created, `bindInstanceFields()` throws an `IllegalStateException`.

The converter list can be augmented with custom converters by extending `Binder` and overriding `getConverterFactory()`, so that it returns a custom `ConverterFactory` implementation. When using a custom converter factory, it’s good practice to fall back to the default one if there is no specific match for the type to be converted.

For example, providing a custom `ConverterFactory` for `Binder` might look like this:

```java
class CustomBinder<BEAN> extends Binder<BEAN> {

    private final ConverterFactory converterFactory = new CustomConverterFactory(super.getConverterFactory());

    @Override
    protected ConverterFactory getConverterFactory() {
        return converterFactory;
    }
}

class CustomConverterFactory implements ConverterFactory {

    private final ConverterFactory fallback;

    CustomConverterFactory(ConverterFactory fallback) {
        this.fallback = fallback;
    }

    public <P, M> Optional<Converter<P, M>> newInstance(Class<P> presentationType, Class<M> modelType) {
        return getCustomConverter(presentationType, modelType)
                .or(() -> fallback.newInstance(presentationType, modelType));
    }

    private <P, M> Optional<Converter<P, M>> getCustomConverter(Class<P> presentationType, Class<M> modelType) {
        // custom logic
        return ...;
    }
}
```

## <a id="using-jsr-303-bean-validation"></a>Using JSR 303 Bean Validation

You can use `BeanValidationBinder` if you prefer to use Java Specification Requests (JSR) 303 Bean Validation annotations, such as `Max`, `Min`, and `Size`.

`BeanValidationBinder` extends `Binder` — and therefore has the same API — but its implementation automatically adds validators based on JSR 303 constraints.

To use Bean Validation annotations, you need a JSR 303 implementation, such as Hibernate Validator, available in your classpath. If your environment doesn’t provide the implementation (e.g., Java EE container), you can use the following dependency in Maven:

```xml
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.1.Final</version>
</dependency>
```

### <a id="defining-constraints-for-properties"></a>Defining Constraints for Properties

To use JSR 303 Bean Validation annotations with `BeanValidationBinder`, for example, you would do something like this:

```java
public class Person {
    @Max(2000)
    private int yearOfBirth;

    // Non-standard constraint provided by
    // Hibernate Validator
    @NotEmpty
    private String name;

    // + other fields, constructors, setters and getters
}

BeanValidationBinder<Person> binder =
        new BeanValidationBinder<>(Person.class);

binder.bind(nameField, "name");
binder.forField(yearOfBirthField)
    .withConverter(
        new StringToIntegerConverter("Enter a number"))
    .bind("yearOfBirth");
```

Constraints defined for properties in the bean work in the same way as if configured programmatically when the binding is created. For example, the following code snippets have the same result.

This first example is a declarative Bean Validation annotation:

```java
public class Person {
    @Max(value = 2000, message =
     "Year of Birth must be less than or equal to 2000")
    private int yearOfBirth;
```

This next example is a programmatic validation using Binder specific API:

```java
binder.forField(yearOfBirthField)
  .withValidator(
    yearOfBirth -> yearOfBirth <= 2000,
    "Year of Birth must be less than or equal to 2000")
  .bind(Person::getYearOfBirth, Person::setYearOfBirth);
```

> **Note:** As an alternative to defining constraint annotations for specific properties, you can define constraints at the bean level. However, Vaadin’s `BeanValidationBinder` doesn’t currently support them. It ignores all JSR 303 validations that aren’t assigned directly to properties.

### <a id="automatically-marking-form-fields-as-required"></a>Automatically Marking Form Fields as Required

Some built-in validators in the bean validation API suggest that a value is required in input field. The `BeanValidationBinder` automatically enables the visual "required" indicator using the `HasValue.setRequiredIndicatorVisible(true)` method for properties annotated with such validators.

By default, `@NotNull`, `@NotEmpty` and `@Size` (if `min()` value is greater than 0) configures the field as required. You can change this behavior using the `BeanValidationBinder.setRequiredConfigurator()` method.

As an example, the following shows how you might override the default `@Size` behavior:

```java
binder.setRequiredConfigurator(
        RequiredFieldConfigurator.NOT_EMPTY
            .chain(RequiredFieldConfigurator.NOT_NULL));
```

### <a id="validation-groups"></a>Validation Groups (since V25.3)

A JSR 303 constraint can declare one or more *validation groups*. A group is a marker interface that allows a subset of the constraints of a bean to be validated, instead of all of them at once. This is useful when the same bean is edited in situations that have different requirements — for example, a draft that needs only a title, and a published article that also needs a summary and a body.

Constraints that don’t declare a group belong to the default group, which is represented by the `jakarta.validation.groups.Default` interface. `BeanValidationBinder` validates the constraints of the default group only, unless it’s configured to use other groups.

For example, the following bean declares constraints in the default group, in a `Draft` group, and in a `Publish` group:

```java
public interface Draft {
}

public interface Publish {
}

public class Article {
    // Default group: always validated
    @NotEmpty
    private String title;

    // Publish group only
    @NotEmpty(groups = Publish.class)
    private String summary;

    // Draft and Publish groups, but not the default group
    @Size(min = 10, groups = { Draft.class, Publish.class })
    private String body;

    // + constructors, setters and getters
}
```

#### <a id="configuring-the-groups-to-validate"></a>Configuring the Groups to Validate

Pass the groups to the `BeanValidationBinder` constructor, or set them afterwards with the `setValidationGroups()` method. The configured groups apply to all validation the binder triggers, including the validation of a single field when its value changes:

```java
BeanValidationBinder<Article> binder =
        new BeanValidationBinder<>(Article.class, Publish.class);

// Or, after the binder has been created:
binder.setValidationGroups(Publish.class);
```

Validation groups replace, rather than extend, the default group. In the example above, the `@NotEmpty` constraint on the `title` property is no longer validated, because it belongs to the default group. To validate the default group as well, list it explicitly:

```java
binder.setValidationGroups(Default.class, Publish.class);
```

Calling `setValidationGroups()` without arguments restores the default behavior of validating the default group only. The `getValidationGroups()` method returns the groups that are in effect, where an empty array means the default group.

A validation group has to be an interface, as required by the Jakarta Bean Validation specification. Passing anything else throws an `IllegalArgumentException`.

> **Note:** Changing the groups doesn’t update validation results that are already displayed. Call `validate()` after `setValidationGroups()` if the fields have already been validated against the previous groups.

#### <a id="validating-other-groups-on-demand"></a>Validating Other Groups on Demand

Some constraints are relevant only when the data is saved, and displaying their error messages while the user is still filling in the form is distracting. For these cases, the `validate()` and `isValid()` methods accept the validation groups to use for that single validation, leaving the configured groups untouched:

```java
publishButton.addClickListener(event -> {
    if (binder.validate(Default.class, Publish.class).isOk()) {
        articleService.publish(article);
    }
});
```

Any validation triggered later — for example, by a field value change — uses the configured groups again.

`validate()` displays the validation results to the user by marking the invalid fields, whereas `isValid()` neither modifies the UI nor fires status change events, which makes it suitable for tasks such as enabling and disabling a save button. Passing an empty array of groups to either method validates against the configured groups.

#### <a id="required-indicators"></a>Required Indicators

The required indicator that `BeanValidationBinder` sets automatically follows the configured validation groups. A field is marked as required only when a constraint that implies a required value — see [Automatically Marking Form Fields as Required](#automatically-marking-form-fields-as-required) — belongs to a group that’s validated. A field whose only such constraint declares a group that isn’t validated, for instance `@NotNull(groups = Save.class)` on a binder with no groups configured, doesn’t get a required indicator.

Reconfiguring the groups with `setValidationGroups()` updates the indicators of the fields that are already bound. An indicator that the application has changed itself after the field was bound is left alone, so that `setRequiredIndicatorVisible()` calls made by the application aren’t overridden.

The indicators follow the configured groups rather than the groups of a single `validate()` or `isValid()` call, so that they reflect what’s validated while the user is editing.

#### <a id="group-inheritance-sequences"></a>Group Inheritance & Sequences

A validation group can extend another group. Validating against the sub-interface also validates the constraints of the groups it inherits from:

```java
public interface FinalPublish extends Publish {
}

// Validates the constraints of both FinalPublish and Publish
binder.setValidationGroups(FinalPublish.class);
```

A group can also be declared as a `@GroupSequence` of other groups. The binder validates the constraints of the groups in the sequence, and takes them into account for the required indicators. The groups of a sequence are validated in the declared order, and validation stops at the first group that has violations:

```java
@GroupSequence({ Draft.class, Publish.class })
public interface FullPublish {
}

// Validates the constraints of the Draft group, and,
// if they pass, those of the Publish group
binder.setValidationGroups(FullPublish.class);
```

A `@GroupSequence` on a bean type redefines the default group of that type. The groups of such a sequence are therefore validated, and taken into account for the required indicators, whenever the default group is validated:

```java
@GroupSequence({ Draft.class, Draftable.class })
public class Draftable {
    // Validated even though the binder has no groups configured
    @NotEmpty(groups = Draft.class)
    private String title;
}
```

#### <a id="bean-level-validators"></a>Bean-Level Validators

`BeanValidationBinder` ignores JSR 303 constraints that aren’t assigned directly to properties, so class-level constraints have to be implemented as bean-level validators added with `withValidator()`. Such a validator can read the groups that are in effect from the binder, which allows it to validate the same groups as the field-level validation:

```java
binder.withValidator((article, context) -> {
    BeanValidationBinder<?> source =
            (BeanValidationBinder<?>) context.getBinder().orElseThrow();
    Class<?>[] groups = source.getValidationGroups();
    // Run the class-level checks that apply to these groups
    return ValidationResult.ok();
});
```

While a `validate()` or `isValid()` call that was given validation groups is running, `getValidationGroups()` returns the groups given to that method instead of the configured ones.

#### <a id="validation-groups-in-beanvalidator"></a>Validation Groups in BeanValidator

`BeanValidationBinder` adds a `BeanValidator` to each binding for you. When you add one to a plain `Binder` instead, pass the validation groups to its constructor:

```java
binder.forField(summaryField)
    .withValidator(new BeanValidator(
        Article.class, "summary", Publish.class))
    .bind(Article::getSummary, Article::setSummary);
```

A `SerializableSupplier` of groups can be given in place of a fixed array. The supplier is queried on every validation, which allows the groups to change after the validator has been created:

```java
binder.forField(summaryField)
    .withValidator(new BeanValidator(
        Article.class, "summary", this::getCurrentGroups))
    .bind(Article::getSummary, Article::setSummary);
```

The `BeanValidator.getValidationGroups()` method returns the groups the validator validates against, where an empty array means the default group.

`D8AE5573-0248-4DBC-A58E-CBEA8E8F0957`
