Automatic Form Generation

The JPAContainer FieldFactory is an implementation of the FormFieldFactory and TableFieldFactory interfaces that can generate fields based on JPA annotations in a POJO. It goes further than the DefaultFieldFactory, which only creates simple fields for the basic data types. This way, you can easily create forms to input entities or enable editing in tables.

The generated defaults are as follows:

AnnotationClass Mapping

@ManyToOne

NativeSelect

@OneToOne, @Embedded

Nested Form

@OneToMany, @ElementCollection

MasterDetailEditor (see below)

@ManyToMany

Selectable Table

The field factory is recursive, so that you can edit a complex object tree with one form.

Configuring the Field Factory

The FieldFactory is highly configurable with various configuration settings and by extending.

The setMultiSelectType() and setSingleSelectType() allow you to specify a selection component that is used instead of the default for a field with @ManyToMany and @ManyToOne annotation, respectively. The first parameter is the class type of the field, and the second parameter is the class type of a selection component. It must be a sub-class of AbstractSelect.

The setVisibleProperties() controls which properties (fields) are visible in generated forms, subforms, and tables. The first paramater is the class type for which the setting should be made, followed by the IDs of the visible properties.

The configuration should be done before binding the form to a data source as that is when the field generation is done.

Further configuration must be done by extending the many protected methods. Please see the API documentation for the complete list.

Using the Field Factory

The most basic use case for the JPAContainer FieldFactory is with a Form bound to a container item:

// Have a persistent container
final JPAContainer<Country> countries =
    JPAContainerFactory.make(Country.class, "book-examples");

// For selecting an item to edit
final ComboBox countrySelect =
    new ComboBox("Select a Country", countries);
countrySelect.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY);
countrySelect.setItemCaptionPropertyId("name");

// Country Editor
final Form  countryForm  = new Form();
countryForm.setCaption("Country Editor");
countryForm.addStyleName("bordered"); // Custom style
countryForm.setWidth("420px");
countryForm.setBuffered(true);
countryForm.setEnabled(false);

// When an item is selected from the list...
countrySelect.addValueChangeListener(new ValueChangeListener(){
    @Override
    public void valueChange(ValueChangeEvent event) {
        // Get the item to edit in the form
        Item countryItem =
            countries.getItem(event.getProperty().getValue());

        // Use a JPAContainer field factory
        //  - no configuration is needed here
        final FieldFactory fieldFactory = new FieldFactory();
        countryForm.setFormFieldFactory(fieldFactory);

        // Edit the item in the form
        countryForm.setItemDataSource(countryItem);
        countryForm.setEnabled(true);

        // Handle saves on the form
        final Button save = new Button("Save");
        countryForm.getFooter().removeAllComponents();
        countryForm.getFooter().addComponent(save);
        save.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                try {
                    countryForm.commit();
                    countryForm.setEnabled(false);
                } catch (InvalidValueException e) {
                }
            }
        });
    }
});
countrySelect.setImmediate(true);
countrySelect.setNullSelectionAllowed(false);

This would create a form shown in Using FieldFactory with One-to-Many Relationship.

Using FieldFactory with One-to-Many Relationship

If you use Hibernate, you also need to pass an EntityManagerPerRequestHelper, either for the constructor or with setEntityManagerPerRequestHelper() , as described in "The EntityManager-Per-Request pattern" .

Master-Detail Editor

The MasterDetailEditor is a field component that allows editing an item property that has one-to-many relationship. The item can be a row in a table or bound to a form. It displays the referenced collection as an editable Table and allows adding and removing items in it.

You can use the MasterDetailEditor manually, or perhaps more commonly use a JPAContainer FieldFactory to create it automatically. As shown in the example in Using FieldFactory with One-to-Many Relationship, the factory creates a MasterDetailEditor for all properties with a @OneToMany or an @ElementCollection annotation.