Binding to Vaadin Flow UI controls

With Seife you can generate code for Vaadin forms and Vaadin grids with just a few and clean directives.
In the JPA model, add @SeifeClass next to @Entity and each attribute that you want to bind to a form field or grid is annotated with @SeifeField.

@Entity
@SeifeClass // just add this for the form binding, no special options needed
public class Customer {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    /**
     * This field is exposed to the forms via @SeifeField
     */
    @SeifeField
    private String firstName;

    /**
     * The mandatory flag will create a mandatory input field whenever it is bound.
     */
    @SeifeField(mandatory = true)
    private String lastName;

    /**
     * Embedded address, this can also be a regular database reference
     */
    @SeifeField
    @Embedded
    private Address address;
// [..]
}

Simple enough, your user control gets the @SeifeForm(forClass=Model.class) annotation to indicate that it is a form or grid for your datamodel. It is enough to mark each field with the @SeifeBinding annotation. In this example a Grid control for the customer class es defined.

@SpringComponent
@Scope(SCOPE_PROTOTYPE)
@SeifeForm(forClass = Customer.class, generatorOptions = {"grid.gridClass"})
public class CustomerGrid extends Grid<Customer> {

    /**
     * The recommended way is to name the fields just as in e.g. {@link Customer}, fields are then bound implicitly.
     */
    @SeifeBinding
    private Column<Customer> firstName;

    /**
     * However if necessary it can be explicitly bound via the name.
     */
    @SeifeBinding("lastName")
    private Column<Customer> name;

    /**
     * You can navigate fields with the dot-notation, even if they may contain null and are not mandatory.
     */
    @SeifeBinding("address.street")
    private Column<Customer> street;
// [..]
}

No additional abstraction layer and dependency to another library is required. The licensed version allows to create your own templates and adjust existing templates to your needs.

Your benefit is a clean and consistent code throughout the whole project, if a datatype changes in the future, a template adjustment will be effective for every user interface that is bound to it.
You may check an excerpt of the generated code for the grid below.

	protected final void setupColumns() {
		firstName = addColumn(entity -> entity.getFirstName());
		firstName.setKey(COLUMN_FIRST_NAME);
		firstName.setId("firstName");
		name = addColumn(entity -> entity.getLastName());
		name.setKey(COLUMN_LAST_NAME);
		name.setId("name");
		street = addColumn(entity -> Optional.ofNullable(entity.getAddress()).map(p -> p.getStreet()).orElse(null));
		street.setKey(COLUMN_ADDRESS_STREET);
		street.setId("street");
		birthday = addColumn(entity -> entity.getBirthday());
		birthday.setKey(COLUMN_BIRTHDAY);
		birthday.setId("birthday");
		password = addColumn(entity -> entity.getPassword());
		password.setKey(COLUMN_PASSWORD);
		password.setId("password");
		favoriteProductName = addColumn(entity -> Optional.ofNullable(entity.getFavoriteProduct()).map(p -> p.getName()).orElse(null));
		favoriteProductName.setKey(COLUMN_FAVORITE_PRODUCT_NAME);
		favoriteProductName.setId("favoriteProductName");
		premium = addComponentColumn(entity -> {
				Checkbox cb = new Checkbox(entity.isPremium());
				cb.setEnabled(false);
				return cb;
			});
 	}

This makes it possible to define the bindings in a declarative way without loosing the expressiveness of plain code and debug information.
The system is able to automatically add e.g. checkboxes whenever a boolean or java.lang.Boolean datatype occurs in your model and it handles custom type bindings in the same way.

See the working example that is part of the full version or trial-archive available for download.