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 result is bit similar to what you can achieve with Spring Roo, as described in Section 14.4, “Creating Vaadin Application and CRUD Views”. However, the form views are generated dynamically at run-time, whereas Roo generates static form views.

The generated defaults are as follows:

Annotation

Class Mapping

@ManyToOne

NativeSelect

@OneToOne, @Embedded

Nested Form

@OneToMany, @ElementCollection

MasterDetailEditor (see below)

@ManyToMany

Selectable Table

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

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 Select countrySelect = new Select("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.setWriteThrough(false); // Enable buffering
countryForm.setEnabled(false);

// When an item is selected from the list...
countrySelect.addListener(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.addListener(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 Figure 18.6, “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 Section 18.9.2, “The EntityManager-Per-Request pattern”.