Select Nested JavaBeans With a Vaadin FieldGroup

Among the long list of improvements that Vaadin 7 brought to us developers is a completely overhauled form binding component that allows binding a data item to a form layout in a much more convenient way than was possible with a former Vaadin version. The new class FieldGroup of Vaadin 7 allows for both an automatic creation of form input fields and binding a data item to an existing layout. Furthermore, class FieldGroup by default runs in a buffered mode which makes it possible to have transactional forms with commit/rollback functionality.

In this blog post, I don’t want to elaborate on the basic usage of the FieldGroup component. You can get a good grasp of this feature in the Book of Vaadin. Instead, we want to take a look on a more advanced usage pattern for FieldGroups that goes beyond simply binding a flat item data model to a form. In this article, we want to explore how we can edit entities that contain nested entity properties by using a drop-down selection to select such a nested entity in a form.

tl;dr: Use a custom implementation of the com.vaadin.data.util.converter.Converter interface to convert between a Container‘s item ID type and the JavaBean type managed by the Container. Set this implementation as converter for a selection component which is used to select a JavaBean entity in a FieldGroup-backed form.

Our goal: select an item from a list of entities

Let’s imagine having the following simple data model. In our application, we want to manage a list of employees together with information about the department in which they work in our company. For the sake of simplicity, our Employee entity takes a first name, a last name, and a reference to a Department entity. The Department entity takes the department’s name and the name of the department manager.

If we want to create a new Employee record with a form, we need a way to select the employee’s department from the list of available departments in our company. We typically want to do that with a selection component such as a ComboBox. The question we’re now facing is, how does Vaadin’s FieldGroup component handle this type of referenced data?

The short and easy answer is: if you use a BeanItemContainer as the data model for the department selection ComboBox and a BeanItem as the item data source for your form, we don’t have to care. The form’s data binding mechanism will just work out of the box and automatically takes care of setting the selected Department instance on the edited Employee object. That is, when selecting a particular department entity from the drop-down list, the FieldGroup‘s data binding mechanism will automatically set the selected item as reference in the Employee entity.

It gets a bit more challenging if we use some other container implementation than a BeanItemContainer as data model for the ComboBox, e.g. when the list of available department entities is managed by a JPAContainer or an IndexedContainer. We’ll look into these two cases in the following sections. We will explore what we have to do for the data binding to work if we use either a BeanItemContainer or some other Container implementation as container data source of a selection component.

FieldGroup data binding behind the scenes

Let’s first have a look at how the FieldGroup component’s data binding works behind the scenes. The main task of FieldGroup is to bind a set of UI field components to a data model kept in a Vaadin Item instance. By that, the user can edit the Item‘s properties through the form, while the FieldGroup provides transactional and validation facilities. Internally, the FieldGroup sets the property data source of each input field of the form to the corresponding item property of the edited item. Therefore, it is mandatory that the data type of the item property matches the data type of the input field in the UI. For example, the firstName property of a BeanItem<Employee> would be set by the FieldGroup as property data source for a text field. Both the text field’s data type and the firstName property’s data type is String, so they match and everything is fine. In cases where there is a mismatch, we would have to provide some conversion mechanism which we will see shortly.

What happens when we bind a selection component (Table, ComboBox, OptionGroup, etc.) to an Item‘s property? Well, that depends on the Container data source of the selection component. All Vaadin selection components derive from the common base class com.vaadin.ui.AbstractSelect which in turn derives from com.vaadin.ui.AbstractField<T>. A selection component thus has an own Property (inherited from AbstractField) in which it stores the currently selected item. The value of this property depends on whether the selection component is in single or multiple selection mode. In single selection mode, the item ID of the current selection is held in the selection component’s property. In multiple selection mode, the property contains a Set<Object> of the selected item IDs. The concrete type of the Item IDs depends on the Container implementation used as the selection component’s data source. For example, the Item ID type of a com.vaadin.data.util.IndexedContainer is Integer, and the Item ID type of a com.vaadin.data.util.BeanItemContainer is the type of the contained JavaBeans.

If we use a selection component in a form, for example an OptionGroup or a ComboBox, we have to take care that the data type of this component’s Property matches the data type of the corresponding Property of the edited item. Since the selection property contains the item ID of the selected item, this basically means that the item ID type has to match the edited property’s data type. The concrete type of the item ID depends on the implementation of the Container that is set as the selection component’s container data source, as we have seen above. We’ll first have a look at Vaadin’s BeanItem* classes to get an idea how Vaadin manages the data types for these classes.

FieldGroups, BeanItems, and BeanItemContainer

Vaadin’s excellent support for JavaBean instances makes it very easy for us to bind our model classes directly to UI components. When we use the classes related to the com.vaadin.data.util.BeanItem implementation (i.e., BeanItemContainer and BeanFieldGroup), FieldGroup‘s data binding will just work out of the box.

We’ll look at a concrete example. Let us first define our data model. As stated above, we need two entity classes Employee and Department:

public class Department {
  private String name;  
  private String departmentManager;

  // + getter and setter methods
}
public class Employee {
  private String firstName;
  private String lastName;
  private Department department;

  // + getter and setter methods
}

We now want to create a form for editing Employee instances using Vaadin’s BeanItem* classes. The reference to an employee’s department shall be selectable with a ComboBox. To do that, we need a BeanItem<Employee> as the form’s data model. Together with a BeanFieldGroup<Employee>, we can bind this BeanItem to a form layout. Let’s compose our input form:

public class EmployeeForm extends CustomComponent
    implements Button.ClickListener {

  private TextField firstName;
  private TextField lastName;
  private ComboBox department;
  private Button okBtn, discardBtn;
  private BeanFieldGroup<Employee> fieldGroup;

  public EmployeeForm(Employee editedEmployee, 
                      Container departments) {
    FormLayout layout = new FormLayout();
    firstName = new TextField("First name");
    lastName = new TextField("Last name");

    department = new ComboBox("Department");
    department.setContainerDataSource(departments);

    layout.addComponent(firstName);
    layout.addComponent(lastName);
    layout.addComponent(department);

    // add form buttons
    HorizontalLayout buttonBar = new HorizontalLayout();
    okBtn = new Button("Ok");
    okBtn.addClickListener(this);
    discardBtn = new Button("Discard");
    discardBtn.addClickListener(this);
    buttonBar.addComponent(okBtn);
    buttonBar.addComponent(discardBtn);
    layout.addComponent(buttonBar);

    // create FieldGroup
    fieldGroup = new BeanFieldGroup<Employee>(Employee.class);
    fieldGroup.setItemDataSource(editedEmployee);
    fieldGroup.bindMemberFields(this);
    
    setCompositionRoot(layout);
  }

  @Override
  public void buttonClick(ClickEvent event) {
    if (event.getSource() == okBtn) {
      try {
        fieldGroup.commit();
        Notification.show("Edited employee: " 
            + fieldGroup.getItemDataSource().getBean(),
            Notification.Type.TRAY_NOTIFICATION);
      } catch (CommitException e) {
        Notification.show("Validation failed: " 
         + "Unable to commit input."
         , Notification.Type.ERROR_MESSAGE);
      }
    } else {
      fieldGroup.discard();
    }
  }
}

Here we create a CustomComponent that contains the form for editing an Employee instance. We pass this instance into the form through the constructor. In addition, we pass in a Container instance which contains the data model for the department ComboBox. We set the data model for the ComboBox with

department.setContainerDataSource(departments);

At the end of the constructor, we create the BeanFieldGroup<Employee> which binds the editedEmployee to the EmployeeForm. We set the data model of the FieldGroup with

fieldGroup.setItemDataSource(editedEmployee);

Lastly, we tell the FieldGroup to do the data binding with

fieldGroup.bindMemberFields(this);

One of the really nice features of FieldGroup is its automatic data binding via reflection. If we use input components in our form whose instance variables have the same name as the properties of the bound item, FieldGroup will be able to bind the form’s field instances to the item properties all by itself. In our example, we have an Employee property firstName and a corresponding text field firstName which are bound together by the FieldGroup automatically. In case the property and field names do not match, you can annotate a form field with the @PropertyId annotation to allow for the automatic field binding. See my blog post “An Overview of Vaadin 7 Annotations” for a description of this annotation.

The next thing we will do with our EmployeeForm is to create an instance of it and add it to our application.

List<Department> departments = departmentDAO.loadDepartments();
BeanItemContainer<Department> departmentContainer = 
   new BeanItemContainer<>(Department.class, departments);

EmployeeForm form = 
   new EmployeeForm(new Employee(), departmentContainer);
mainLayout.addComponent(form);

In this code snippet, we create a new instance of EmployeeForm and initialize it with a BeanItemContainer<Department>. The container is prefilled with a list of Department entities loaded from the database. This container will serve as the data model of the department selection ComboBox.

What will now happen when the user fills out this form, selects some department object from the ComboBox, and presses the OK button? The BeanItemContainer internally uses the bean type as its item ID type. That is, the item ID of the selected item is the selected Department instance itself. This is convenient, since this ID can be directly passed through to the department property of the BeanItem<Employee> which is bound to the form. As we can see, there’s nothing else for us to do in this case – we have a fully functioning form which allows us to select nested entities.

All other Container implementations

That was easy so far. Let us now have a look at other implementations of the Container interface, such as IndexedContainer or JPAContainer. These implementations do not use a JavaBean instance as item ID. Typically, they use an implementation-specific item ID. For instance, IndexedContainer uses the one-based position of an item in the container as its ID (i.e., the item added first to the container has item ID 1). When we use such an implementation as the data model for a selection component, we have a mismatch between the item ID type and the edited item property’s type.

We’ll adapt the example from above a bit: to demonstrate this

IndexedContainer departmentContainer = new IndexedContainer();
departmentContainer.addContainerProperty("name", String.class, "");
departmentContainer.addContainerProperty("bean", Department.class, null);

// fill container with the available departments
List<Department> departments = departmentDAO.loadDepartments();
for (Department department : departments) {
  Object itemId = departmentContainer.addItem();
  Item item = departmentContainer.getItem(itemId);
  item.getItemProperty("name").setValue(department.getName());
  item.getItemProperty("bean").setValue(department);
}

EmployeeForm form = 
   new EmployeeForm(new Employee(), departmentContainer);

Instead of using a BeanItemContainer, we now instantiate an IndexedContainer, fill it with our department entities and pass that instance to the EmployeeForm. When using an IndexedContainer we have to take care of properly configuring the container’s properties ourselves. In this case, we only need two properties: the name of a department (to be used as item caption for the ComboBox; the ComboBox‘s item caption mode would have to be explicitly set to ItemCaptionMode.PROPERTY in EmployeeForm) and a property “bean” holding a reference to the department entity (this reference will later be set on the edited employee when selected).

If we use this setup in our form, we will experience an exception when committing the FieldGroup. This is because the data type of the IndexedContainer‘s item ID (Integer) does not match the data type of the Employee item’s department property (Department).

Bringing together item ID type and property type

How can we consolidate the container’s item ID type and the edited entity’s property type? Using Vaadin’s com.vaadin.data.util.converter.Converter interface introduced with Vaadin 7 makes this a breeze. All we have to do is write a custom implementation of Converter which converts an item ID into its corresponding entity and vice versa. We then set an instance of this converter on the ComboBox.

A Converter implementation is configured with two generic parameters: a presentation type and a model type. The signature of Converter is thus Converter<PRESENTATION, MODEL>. A converter will convert between these two types. In our case, PRESENTATION is the type of the item ID which is an Object for a Vaadin Container. MODEL is the type of the entity which shall be selectable by the selection component. This is the Department JavaBean in our example. In our Converter implementation, we have to take care of the conversion between these two types. We do this as follows:

import com.vaadin.data.util.IndexedContainer;
import com.vaadin.data.util.converter.Converter;

public class IndexToDepartmentConverter implements Converter<Object, Department> {

  private IndexedContainer container;

  public IndexToDepartmentConverter(IndexedContainer container) {
    this.container = container;
  }

  @Override
  public Department convertToModel(Object itemID,
      Class<? extends Department> targetType, Locale locale)
      throws com.vaadin.data.util.converter.Converter.ConversionException {
    if (itemID == null) {
      return null;
    }

    Item item = container.getItem(itemID);
    if (item == null) {
      return null;
    }

    Department model = (Department) item.getItemProperty("bean").getValue();
    return model;
  }

  @Override
  public Integer convertToPresentation(Department model,
      Class<? extends Object> targetType, Locale locale)
      throws com.vaadin.data.util.converter.Converter.ConversionException {

    for (Object itemId : container.getItemIds()) {
      Item item = container.getItem(itemId);
      if (model.equals((Department) item.getItemProperty("bean").getValue())) {
        return (Integer) itemId;
      }
    }

    return null;
  }

  @Override
  public Class<Department> getModelType() {
    return Department.class;
  }

  @Override
  public Class<Object> getPresentationType() {
    return Object.class;
  }
}

Let’s go through this implementation step by step. We name our converter class IndexToDepartmentConverter as we want to convert the one-based index of an entity contained in an IndexedContainer into a Department entity and vice versa. For this conversion, we will fetch the entity instance directly from the data of the IndexedContainer. As we have seen above, we added a property with ID bean, which contains the concrete Department instance, to the container. Therefore, we pass an instance of the IndexedContainer to the constructor of our converter. We will use this reference in our conversion methods.

The first conversion method convertToModel() converts a given item ID into the model type, i.e. a Department instance. We do that by fetching from the container the Item referenced by the itemID and retrieve the bean property from it.

The inverse operation convertToPresentation() determines the ID of the item that contains a given Department instance. For simplicity’s sake we do this by iterating over all items in the container and return the item ID of the item that contains the given Deparment instance. Of course, one can think of a lot more sophisticated implementations for this task than iterating over all available items (such as fetching the item ID from a map). The approach from the example could kill your performance – you have been warned…

The last two methods to be implemented for a Converter, getModelType() and getPresentationType() simply have to return the class objects for the model and presentation types.

That’s basically it. We have our converter ready for action, and can add an instance of it to the ComboBox in our form. To do that, we enhance the signature of our form class:

public EmployeeForm(Employee editedEmployee, 
                    Container departments, 
                    Converter converter) {
    department = new ComboBox("Department");
    department.setContainerDataSource(departments);
    
    if (converter != null) {
        department.setConverter(converter);
    }
    // ...
}

The form component can now be created like this:

IndexedContainer departmentContainer = new IndexedContainer();
// ...
IndexToDepartmentConverter converter = 
   new IndexToDepartmentConverter(departmentContainer);
EmployeeForm form = 
   new EmployeeForm(new Employee(), departmentContainer,
   converter);

Using this setup, we can use an arbitrary implementation of the Container interface as the data model for a selection component in a FieldGroup-backed form. We only have to provide a matching Converter implementation for this container. Note that before writing a custom converter for a particular Container implementation, you should first check if this Container implementation does not provide its own converter implementation. For example, Vaadin’s JPAContainer add-on provides a custom converter implementation com.vaadin.addon.jpacontainer.fieldfactory.SingleSelectConverter which can be used for exactly the same scenario as described in this tutorial. Make sure that you also take a look at JPAContainer’s class com.vaadin.addon.jpacontainer.fieldfactory.FieldFactory which will create preconfigured many-to-many and many-to-one selection components for you.

You’ll find a working example for this blog post in my GitHub repository. You can play around with this example in this demo application.

Short URL for this post: http://blog.oio.de/cjC9M
This entry was posted in Java Web Frameworks and tagged , , , . Bookmark the permalink.

8 Responses to Select Nested JavaBeans With a Vaadin FieldGroup

  1. Robert Reiz says:

    A lot of code for a simple HTML select. That’s the Enterprise way of generating a bit HTML and storing a couple values in the database.
    A Rails developer gets the job done in 15 min, with a couple lines of Ruby and HTML code. It’s really not that complicated.

    • Papick G. Taboada Papick G. Taboada says:

      Ok! Flame war, here we go!

      A rails/ grails developer will get lot of things done faster. I have me roots in perl and I miss it in so many ways. But not when it comes to software maintenance.

      In the long run, maintainance is the costly thing in a software.
      Yes, one can screw up in so many levels it is hard to count, but this is no excuse for not trying.

      I won’t give up fail fast, fail early.
      I won’t give up compiler errors.
      I won’t give up refactoring tools.

    • Roland Krüger Roland Krüger says:

      I’m afraid you’re completely missing the point of this blog post. This is not about how to create a simple HTML select with Vaadin. You can do this as simple as

      ComboBox select = new ComboBox();
      select.addItem(“One”);
      select.addItem(“Two”);
      select.addItem(“Three”);
      layout.addComponent(select);

      Besides, the article’s code example does slightly more than just create and populate a single HTML select ;-)

      This article is about how to correctly use Vaadin’s data binding feature for advanced use cases where you want to edit a one-to-many relationship in a form. As Papick writes below, all of this is about separation of concerns which leads to better maintainability and testability in the long run.

      • Robert Reiz says:

        I don’t think that over engineering is easier to maintain.

        Just because a language is dynamic it doesn’t mean that it’s hard to maintain or it leads to bad software design. Design concepts like separation of concerns are not unknown in the Ruby/Python/NodeJS world ;-)

        Some guys in the Bay Area are using tools like Vim, SubLime & git cmd to build GitHub, Heroku, Airbnb and the Linux Kernel.

        Some other guys in Germany need a 500 MB tool to edit a bunch of *.java text files to build an Enterprise application, which is usually used by less than 1K people and don’t need to scale at all. Isn’t that funny?

        Most Java Devs are investing weeks and months to learn about component frameworks, life-cycles, bindings, CDIs and RFCs. But they now almost nothing about HTTP, HTML, CSS & JavaScript. I guess that’s evil. We should abstract it away in component frameworks. Right? :-)

  2. Victor R. says:

    Hi Roland,

    thanks for you very informative blog posts that also have a high quality.
    I read several of them meanwhile and find them very useful.

    So from my side a big “thank you” for sharing your knowledge and experience!

    Victor

    • Roland Krüger Roland Krüger says:

      Thanks a lot for your comment. This is much appreciated! You can expect more Vaadin articles to come in the future.

  3. Nguyen Vo says:

    Can I use collection with textfield ? ur example is combobox.

    • Roland Krüger Roland Krüger says:

      I’m not sure if I understand you correctly. Do you mean to select a value from a collection by entering this value into a textfield? If so, you also have to write a converter that converts the text entered into the textfield into a corresponding value from the collection.

Leave a Reply