Container is the highest-level of the data model interfaces supported by Vaadin. It provides a very flexible way of managing a set of items that share common properties. Contained items are identified by an item identifier or IID.

Items can be added to a container with the addItem() method. Notice that the actual item is not passed as a parameter to the method, only the item ID, as the interface assumes that the container implementation knows how to create the item. The parameterless version of the method uses an automatically generated item ID. Implementations can provide methods to add externally created items, or they can assume that the item ID is also the item itself.

Properties can be requested from container by first requesting an item with getItem() and then getting the properties from the item with getItemProperty(). You can also get a property directly by the item and property ids with getContainerProperty().

The Container interface was designed with flexibility and efficiency in mind. It contains inner interfaces that containers can optionally implement for ordering the items sequentially, indexing the items, and accessing them hierarchically. Such ordering models provide the basis for the Table, Tree, and Select components. As with other data model interfaces, the Container supports events for notifying about changes made to their contents.

As containers can be unordered, ordered, indexed, or hierarchical, they can interface practically any kind of data representation. Vaadin includes data connectors for some common data sources, such as the simple tabular data, with IndexedContainer, and the filesystem, with FilesystemContainer.

In addition to generic container implementations, also many user interface components are containers as themselves, in addition to being properties. This is especially true for selection components, that is, those that implement Select, because they are containers that contain selectable items. Their property is the currently selected item. This is useful as it allows binding components to view and updating each others' data directly, and makes it easy to reuse already constructed data models, for example, a form could edit a row (item) of a table directly, and the table could use a database container as its underlying container. The fields of the form would correspond to the properties of the item, that is, the cells of the table row.

The library contains a set of utilities for converting between different container implementations by adding external ordering or hierarchy into existing containers. In-memory containers implementing indexed and hierarchical models provide easy-to-use tools for setting up in-memory data storages. Such default container implementations include IndexedContainer, which can be thought of as a generalization of a two-dimensional data table, and BeanItemContainer, which maps standard Java objects (beans) to items of an indexed container. In addition, the built-in containers include a hierarchical container for direct file system browsing.

The BeanContainer is an in-memory container for JavaBean objects. Each contained bean is wrapped inside a BeanItem wrapper. The item properties are determined automatically by inspecting the getter and setter methods of the class. This requires that the bean class has public visibility, local classes for example are not allowed. Only beans of the same type can be added to the container.

The generic has two parameters: a bean type and an item identifier type. The item identifiers can be obtained by defining a custom resolver, using a specific item property for the IDs, or by giving item IDs explicitly. As such, it is more general than the BeanItemContainer, which uses the bean object itself as the item identifier, making the use usually simpler. Managing the item IDs makes BeanContainer more complex to use, but it is necessary in some cases where the equals() or hashCode() methods have been reimplemented in the bean.

// Here is a JavaBean
public class Bean implements Serializable {
    String name;
    double energy; // Energy content in kJ/100g
    
    public Bean(String name, double energy) {
        this.name   = name;
        this.energy = energy;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public double getEnergy() {
        return energy;
    }
    
    public void setEnergy(double energy) {
        this.energy = energy;
    }
}

void basic(VerticalLayout layout) {
    // Create a container for such beans with
    // strings as item IDs.
    BeanContainer<String, Bean> beans =
        new BeanContainer<String, Bean>(Bean.class);
    
    // Use the name property as the item ID of the bean
    beans.setBeanIdProperty("name");

    // Add some beans to it
    beans.addBean(new Bean("Mung bean",   1452.0));
    beans.addBean(new Bean("Chickpea",    686.0));
    beans.addBean(new Bean("Lentil",      1477.0));
    beans.addBean(new Bean("Common bean", 129.0));
    beans.addBean(new Bean("Soybean",     1866.0));

    // Bind a table to it
    Table table = new Table("Beans of All Sorts", beans);
    layout.addComponent(table);
}

To use explicit item IDs, use the methods addItem(Object, Object), addItemAfter(Object, Object, Object), and addItemAt(int, Object, Object).

It is not possible to add additional properties to the container, except properties in a nested bean.

If you have a nested bean with a 1:1 relationship inside a bean type contained in a BeanContainer or BeanItemContainer, you can add its properties to the container by specifying them with addNestedContainerProperty(). The feature is defined at the level of AbstractBeanContainer.

As with a top-level bean in a bean container, also a nested bean must have public visibility or otherwise an access exception is thrown. Intermediary getters returning a nested bean must always return a non-null value.

For example, assume that we have the following two beans with the first one nested inside the second one.

/** Bean to be nested */
public class EqCoord implements Serializable {
    double rightAscension; /* In angle hours */
    double declination;    /* In degrees     */

    ... constructor and setters and getters for the properties ...
}

/** Bean containing a nested bean */
public class Star implements Serializable {
    String  name;
    EqCoord equatorial; /* Nested bean */

    ... constructor and setters and getters for the properties ...
}

After creating the container, you can declare the nested properties by specifying their property identifiers with the addNestedContainerProperty() in dot notation.

// Create a container for beans
final BeanItemContainer<Star> stars =
    new BeanItemContainer<Star>(Star.class);

// Declare the nested properties to be used in the container
stars.addNestedContainerProperty("equatorial.rightAscension");
stars.addNestedContainerProperty("equatorial.declination");

// Add some items
stars.addBean(new Star("Sirius",  new EqCoord(6.75, 16.71611)));
stars.addBean(new Star("Polaris", new EqCoord(2.52, 89.26417)));

If you bind such a container to a Table, you probably also need to set the column headers. Notice that the entire nested bean itself is still a property in the container and would be displayed in its own column. The toString() method is used for obtaining the displayed value, which is by default an object reference. You normally do not want this, so you can hide the column with setVisibleColumns().

// Put them in a table
Table table = new Table("Stars", stars);
table.setColumnHeader("equatorial.rightAscension", "RA");
table.setColumnHeader("equatorial.declination",    "Decl");
table.setPageLength(table.size());

// Have to set explicitly to hide the "equatorial" property
table.setVisibleColumns(new Object[]{"name",
    "equatorial.rightAscension", "equatorial.declination"});

The resulting table is shown in Figure 9.4, “Table Bound to a BeanContainer with Nested Properties”.


The bean binding in AbstractBeanContainer normally uses the MethodProperty implementation of the Property interface to access the bean properties using the setter and getter methods. For nested properties, the NestedMethodProperty implementation is used.

BeanItemContainer is a container for JavaBean objects where each bean is wrapped inside a BeanItem wrapper. The item properties are determined automatically by inspecting the getter and setter methods of the class. This requires that the bean class has public visibility, local classes for example are not allowed. Only beans of the same type can be added to the container.

BeanItemContainer is a specialized version of the BeanContainer described in Section 9.4.1, “BeanContainer. It uses the bean itself as the item identifier, which makes it a bit easier to use than BeanContainer in many cases. The latter is, however, needed if the bean has reimplemented the equals() or hashCode() methods.

Let us revisit the example given in Section 9.4.1, “BeanContainer using the BeanItemContainer.

// Create a container for the beans
BeanItemContainer<Bean> beans =
    new BeanItemContainer<Bean>(Bean.class);
    
// Add some beans to it
beans.addBean(new Bean("Mung bean",   1452.0));
beans.addBean(new Bean("Chickpea",    686.0));
beans.addBean(new Bean("Lentil",      1477.0));
beans.addBean(new Bean("Common bean", 129.0));
beans.addBean(new Bean("Soybean",     1866.0));

// Bind a table to it
Table table = new Table("Beans of All Sorts", beans);

It is not possible to add additional properties to a BeanItemContainer, except properties in a nested bean, as described in Section 9.4.1, “BeanContainer.

As the items in a Container are not necessarily indexed, iterating over the items has to be done using an Iterator. The getItemIds() method of Container returns a Collection of item identifiers over which you can iterate. The following example demonstrates a typical case where you iterate over the values of check boxes in a column of a Table component. The context of the example is the example used in Section 5.14, “Table.

// Collect the results of the iteration into this string.
String items = "";

// Iterate over the item identifiers of the table.
for (Iterator i = table.getItemIds().iterator(); i.hasNext();) {
    // Get the current item identifier, which is an integer.
    int iid = (Integer) i.next();
    
    // Now get the actual item from the table.
    Item item = table.getItem(iid);
    
    // And now we can get to the actual checkbox object.
    Button button = (Button)
            (item.getItemProperty("ismember").getValue());
    
    // If the checkbox is selected.
    if ((Boolean)button.getValue() == true) {
        // Do something with the selected item; collect the
        // first names in a string.
        items += item.getItemProperty("First Name")
                     .getValue() + " ";
    }
}

// Do something with the results; display the selected items.
layout.addComponent (new Label("Selected items: " + items));

Notice that the getItemIds() returns an unmodifiable collection, so the Container may not be modified during iteration. You can not, for example, remove items from the Container during iteration. The modification includes modification in another thread. If the Container is modified during iteration, a ConcurrentModificationException is thrown and the iterator may be left in an undefined state.

Containers that implement the Container.Filterable interface can be filtered. For example, the built-in IndexedContainer and the bean item containers implement it. Filtering is typically used for filtering the content of a Table.

Filters implement the Filter interface and you add them to a filterable container with the addContainerFilter() method. Container items that pass the filter condition are kept and shown in the filterable component.

Filter filter = new SimpleStringFilter("name",
        "Douglas", true, false);
table.addContainerFilter(filter);

If multiple filters are added to a container, they are evaluated using the logical AND operator so that only items that are passed by all the filters are kept.

The built-in filter types are the following:

A custom filter needs to implement the Container.Filter interface.

A filter can use a single or multiple properties for the filtering logic. The properties used by the filter must be returned with the appliesToProperty() method. If the filter applies to a user-defined property or properties, it is customary to give the properties as the first argument for the constructor of the filter.

class MyCustomFilter implements Container.Filter {
    protected String propertyId;
    protected String regex;
    
    public MyCustomFilter(String propertyId, String regex) {
        this.propertyId = propertyId;
        this.regex      = regex;
    }

    /** Tells if this filter works on the given property. */
    @Override
    public boolean appliesToProperty(Object propertyId) {
        return propertyId != null &&
               propertyId.equals(this.propertyId);
    }

The actual filtering logic is done in the passesFilter() method, which simply returns true if the item should pass the filter and false if it should be filtered out.

    /** Apply the filter on an item to check if it passes. */
    @Override
    public boolean passesFilter(Object itemId, Item item)
            throws UnsupportedOperationException {
        // Acquire the relevant property from the item object
        Property p = item.getItemProperty(propertyId);
        
        // Should always check validity
        if (p == null || !p.getType().equals(String.class))
            return false;
        String value = (String) p.getValue();
        
        // The actual filter logic
        return value.matches(regex);
    }
}

You can use such a custom filter just like any other:

c.addContainerFilter(
    new MyCustomFilter("Name", (String) tf.getValue()));