Eclipse-Databinding for Vaadin

A while ago we (Lunifera GmbH) have implemented Eclipse-Databinding for Vaadin. Two different databinding approaches that perfectly work together.

In this blog i’d like to talk about the two different ways of databinding and how these worlds can be tided together.

Vaadin comes with an integrated databinding capability. Databinding in Vaadin means, that UI elements (components) are bound to so called containers, items and properties. So the data of components can be abstracted from the component itself. But Vaadin defines no common way to bind these containers, items and properties to each other.

There the eclipse databinding comes into play. Eclipse databinding provides a common way to bind so called “observable values” to each other. An “observale value” is an abstraction above the “data related to its source”. Eclipse databinding comes with an implementation for POJOs, Beans (POJOs with PropertyChangeSupport), SWT-Widgets, JFace-Components, EObjects (Eclipse Modeling Framework – EMF) and the EMF-Edit-Commands. These implementations allow you to bind “observable values” from different domains (one of mentioned implementations) to each other.

In combination Vaadin databinding and Eclipse databinding are working properly together.

Vaadin Databinding

Vaadin databinding consists of 3 concepts for different use cases:

  • Property – An abstraction for a type and value. Used to bind fields like TextField to the property
  • Item – A collection of properties. It represents a row in a table. Each property inside the item has a unique propertyID
  • Container – A collection of items. It represents a data-table. Each item inside the container has a unique itemID

Property, Item and Container are expressed by interface. And Vaadin comes with a lot of proper implementations for different usecases.

datamodel-sml

Image: “Book of Vaadin 8.1” – Copyright 2015 Vaadin Ltd [1].

Property

// Create a property
ObjectProperty property =
    new ObjectProperty("Florian", String.class);
        
// Create a text field
TextField nameField = new TextField("Firstname");
        
// Bind nameField to data
nameField.setPropertyDataSource(property);

See also: “Book of Vaadin 8.2.1”

As soon as the property is set to the field, you may use the property to read and write values.

Item

Dealing with items is really similar to properties.

PropertysetItem item = new PropertysetItem();
item.addItemProperty("firstName", new ObjectProperty("Florian"));
item.addItemProperty("age", new ObjectProperty(36));
        
// create a form
Form form = new Form();
form.setItemDataSource(item);

See also: “Book of Vaadin 8.3.1”

In this case an item is prepared and set to a form. Forms are special components that show defined properties of the given item.

There are different ways to define items. The example above uses a PropertysetItem which allows you to define all properties manually. But there are also more comfortable way for pojos.

// Create an instance of the bean
Person bean = new Person();
        
// Create a bean item configured for type Person.class
BeanItem<Person> item = new BeanItem<Person>(bean);

// Set the item to the form
Form form = new Form();
form.setItemDataSource(item);

Sample: “Book of Vaadin 8.3.2”
To automatically create an item for a bean, that holds each bean-property, you just may use the BeanItem.

Container

// set a personContainer to the table
Table table = new Table("Persons");
table.setContainerDataSource(personContainer);

See also: “Book of Vaadin 8.5”

For containers there is also a generic way to define the container properties (the columns of the container). And also a lot of very useful implementations like the BeanContainer or BeanItemContainer. Based on the JPAContainer you can connect your Vaadin components to JPA really quickly.

For details about BeanItemContainer see: “Book of Vaadin 8.5.4”

Eclipse Databinding

The Eclipse databinding follows a more general way and tries to abstract bindings in general.

Unbenannte Zeichnung (1)If you would like to use Eclipse databinding, you have to deal with some concepts.

  • ObservableValue (ObservableList) – it is defined by an interface and is an abstraction above a data-endpoint.
  • UpdateValueStrategy – defines how source-to-target and target-to-source updates will be processed.
  • Binding – binds the observable values (or lists) to each other. BindingStrategy can be used.
  • DatabindingContext – It is a common state for all contained bindings.
  • Realm – It is responsible to synchronize updates with the environment

Observable Values

Similar to the Vaadin databinding, an obervable value defines the type and value the instance deals with. The observable value knows how to access the underlying “target-element”. This “target-element” may be anything, as far there is an implementation for it. For now the”target-element” may be a pojo, a bean, an EObject, a SWT-widget,… The observable value will register all required listeners at the “target-element” to get notified about changes. If the value of the “target-element” is changed, then the “obervable value” will notify the Binding, which updates the value at the opposite side of the Binding.

UpdateValueStrategy

The UpdateValueStrategy may be used to define how values are updated.They can be defined for “source-to-target” and “target-to-source” updates. The UpdateValueStrategy is also responsible for data conversion.

It comes with 3 policies:

  • POLICY_NEVER – Values in the “observable value” will never be transferred to the opposite end of the binding.
  • POLICY_ON_REQUEST –  Values in the “observable value” will only be transferred to the opposite end, if requested by a method call.
  • POLICY_UPDATE – If the “observable value” becomes notified about changes in the “target-element”, then the value will be automatically transferred to the opposite of the binding.

ValueBinding

The ValueBinding connects the Source-ObservableValue to the Target-ObservableValue according the UpdateValueStrategy-Policy. It also offers methods to validate and update model-to-target or target-to-model (Model is a synonym for Source) operations.

DatabindingContext

The databinding context manages all bindings. Also List- and Set-Bindings. The granularity about the instances of DatabindingContexts depends on the underlying application. In general i would say, that all bindings that should be validated in a common context, should be added to the sames context. If you have different views as part of your system, each view may get its own context. But it depends on you.

Lifecycle

When you are using Eclipse databinding, you need to be aware about its lifecycle. If a view is closed, a timeout occurs,… you must ensure, that the databinding context is #disposed(). There is a method for it. Otherwise the Vaadin components will receive value updates, even if the UI is already closed.

Realm

For instance if you are doing a long running operation as an async operation in a different thread and you expect that the async operation updates your UI properly, you need a way to sync your UI with this thread. In SWT you have to update the UI in the SWT-Ui-Thread. In Vaadin you need to call UI#access(…).

The realm is specific for each databinding implementation. The source- and the target-observable-values may have their own Realm. So it would be possible to bind a SWT-UI to a Vaadin-UI. I never tried to do so, but i am pretty sure, that it will work properly.

Eclipse-Databinding for Vaadin

We have prepared an eclipse databinding implementation for Vaadin. You can find it in this github-repo. There is also a P2-Updatesite located here: Lunifera-P2-Repo.

Realm-Activation

Before you create the DatabindingContext, you need to activate the Realm for VaadinDatabinding.

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

Even if you would like to add new Bindings in a different Thread, you need to activate the realm. Otherwise databinding does not know anything about the current UI-instance.

In real projects you won’t have to call the activation on certain places again and again. So there is a perfect place to do so.

You have to override the VaadinServletService and add following method:

public UI findUI(VaadinRequest request) {
	UI instance = super.findUI(request);

	// activate the realm for the current ui and thread
	VaadinObservables.activateRealm(instance);

	return instance;
}

Then every time, Vaadin is looking for the current UI-instance, the realm will be activated automatically.

 

 

Examples

Now lets start with some examples demonstrating how to use the eclipse databinding for Vaadin.

1 Binding components –> #value

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();
	
// Create the Vaadin components
TextField sourceField = new TextField();
sourceField.setImmediate(true);
Label targetField = new Label();
	
// Create the observable values
IObservableValue sourceOV = VaadinObservables.observeValue(sourceField);
IObservableValue targetOV = VaadinObservables.observeValue(targetField);

// bind the values to each other
dbc.bindValue(sourceOV, targetOV);

This sample binds the value of the textField to the value of the label. If the value of the textField changes, the label is updated.

2 Binding components –> #enabledState

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

// Create the Vaadin components
CheckBox checkbox = new CheckBox();
checkbox.setImmediate(true);
TextField textField = new TextField();
		
// Create the observable values
IObservableValue sourceOV = VaadinObservables.observeValue(checkbox);
// observe the enabled state of the textfield
IObservableValue targetOV = VaadinObservables.observeEnabled(textField);

// bind the values to each other
dbc.bindValue(sourceOV, targetOV);

This sample binds the value of the checkBox to the enabled property of the textfield. If the checkbox is checked, then the textField is enabled. Otherwise it is disabled.

3 Bind components to beans

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

Person person = new Person();

// Create the text field
TextField textField = new TextField();
textField.setImmediate(true);

// Create the observable values
IObservableValue sourceOV = BeansObservables.observeValue(person, "firstname");
IObservableValue targetOV = VaadinObservables.observeValue(textField);

// bind the values to each other
dbc.bindValue(sourceOV, targetOV);

This sample binds the “firstname”-property of the given bean to the value of the text. If the value of the textField or the value of the bean changes, then the change is updated at the opposite site.

4 Reuse the Vaadin property

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

Person person = new Person();

// Create the text field
TextField textField = new TextField();
textField.setImmediate(true);
textField.setPropertyDatasource(new ObjectDatasource());

// Create the observable values
IObservableValue sourceOV = BeansObservables.observeValue(person, "firstname");
textField.setPropertyDataSource(new ObjectProperty<String>("", String.class));

// bind the values to each other
dbc.bindValue(sourceOV, targetOV);

In this sample, an ObjectProperty was set to the textField. The Vaadin databinding implementation internally tries to get the property datasource before binding. If it is available, then the property will be bound. Otherwise the field itself is bound. So it is your choice whether you want to work with properties or not.

5 Bind the multiselection of table-1 to the input of table-2

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

// Create the Vaadin components
Table table1 = new Table();
table1.setMultiSelect(true);
table1.setImmediate(true);
Table table2 = new Table();

// observe the multi selection
IObservableList table1OV = VaadinObservables.observeMultiSelectionAsList(table1, Person.class);
// observe the content
IObservableList table2OV = VaadinObservables.observeContainerItemSetContents(table2, Person.class);
	
// bind the values to each other
dbc.bindList(table1OV, table2OV);

This sample binds the multi-selection of table1 to the input of table2. So table2 shows the selected items of table1. Note, that this kind of binding uses ObservableLists.

 

6 Bind a table to a WritableList

// Activate the realm
VaadinObservables.activateRealm(this);

// Create databinding context
DataBindingContext dbc = new DataBindingContext();

// create a table
Table table = new Table("Persons");
layout.addComponent(table);
table.setContainerDataSource(new BeanItemContainer<Person>(
			Person.class));
		
// create a writable list as model
final WritableList model = new WritableList();
		
// observe the table container content
IObservableList tableOV = VaadinObservables
		.observeContainerItemSetContents(table, Person.class);

// bind the lists to each other
dbc.bindList(model, tableOV);

// create a button to add records
Button button = new Button("Add person");
layout.addComponent(button);
button.addClickListener(new Button.ClickListener() {
	@Override
	public void buttonClick(ClickEvent event) {
		Person person = new Person();
		person.setName("My first name");
		person.setName2("Another name");
		person.setAge(43);
		person.setBirthday(new Date());
		model.add(person);
	}
});

This sample binds a WriteableList as a model to the container contents. If a Person is added to the model, the table will update it’s contents.
The Button is used to add new records to the model.

7 Bind a table to a nested list in a bean or pojo

// Activate the realm
VaadinObservables.activateRealm(this);

final DataBindingContext dbc = new DataBindingContext();

// create a table
Table table = new Table("Persons");
layout.addComponent(table);
table.setContainerDataSource(new BeanItemContainer<Person>(Person.class));

// create the model
final Person father = createPerson("Father", 43);
father.addToChildren(createPerson("Child 1", 17));
father.addToChildren(createPerson("Child 2", 19));

// observe the table container content
IObservableList tableOV = VaadinObservables
		.observeContainerItemSetContents(table, Person.class);
// observe the nested children list
IObservableList childrenOV = BeansObservables.observeList(father,
		"children", Person.class);

// bind the lists to each other
dbc.bindList(tableOV, childrenOV);

// create a button to add records
Button button = new Button("Add person");
layout.addComponent(button);
button.addClickListener(new Button.ClickListener() {
	@Override
	public void buttonClick(Button.ClickEvent event) {
		Person person = new Person();
		person.setName("Child 3");
		person.setAge(23);
		father.addToChildren(person);
		// Update the targets
		dbc.updateTargets();
	}
});

This sample binds a nested children list located in Person.class as a model to the container contents. The Button is used to add new records to the model.

Attention: If a person is added to the children list of the bean, the table is not updated automatically. This happens since the PropertyChangeSupport does not really support notifications for changed collections. So you need to call dbc.updateTargets() or binding.updateModelToTarget().
If you are using the Eclipse Modeling Framework, then also changes in Sets and Lists are automatically transferred to the table, since EMF can deal with notifications for collection changes.

Attention2: If the person bean does not provide PropertyChangeSupport, then you need to use PojoObservables#observeList to create the model observable.

 Conclusion

With “Eclipse Databinding for Vaadin” can bind Vaadin components to other components, beans, pojos,… very quickly. The databinding implementation ensures, that values are treated properly. Using “Eclipse Databinding for Vaadin” developers can save a lot of lines of code.

See also

The examples in these additional sources may also be used for the “Eclipse databinding for Vaadin”. The core concepts are always the same.

[1]  Copyright 2015 Vaadin Ltd, licensed under a Creative Commons CC-BY-ND License version 2.0

Tags: , , , ,

10 Responses to “Eclipse-Databinding for Vaadin”

  1. Michael Says:

    Hey Florian,

    is there a example for Databinding for a Table which contains a IndexedContainer?

    Regards

    Michael

    • Florian Pirchner Says:

      Hey Michael,

      not now. But i will extend the blog this evening or tomorrow and add a sample.
      But i depends on your datasource. If a list or set is located in a bean, then you would use BeanObservables.observeDetail…
      If you would like to add items to a list manually then you should use a WritableList.

      I will provide samples for both in the blog.

      Thanks for that hint.

      Best Florian

  2. Michael Says:

    Hey Florian,

    thanks for your quick reply, my datasource is a EMF object which contains a EList. With a BeanItemContainer it works, but with a IndexedContainer i have to call and that is not very nice:
    Item item = getTable().getContainerDataSource().getItem(id);
    item.getItemProperty(VALUE_COLUMN).setValue(id);

    Best Regards

    Michael

    • Florian Pirchner Says:

      Hey,
      good hint about eobjects. Then you need to use emfobservables.
      Could you please provide me with a basic sample. Only the way how you define and assign the indexed container.
      There are a lot of use cases I can imagine.
      The I will provide you with the solution for it.
      Thanks florian

    • Florian Pirchner Says:

      Hey Michael,

      i have extended the blog yesterday and updated right now. I also did some experiments with the IndexedContainer. The table does not show any property values. But the rows are being added to the table properly.

      In my opinion this is not a problem caused by DataBinding. The IndexedContainer#IndexedContainerItem does not know how to access the values contained in the EObject.

      So i would suggest to use the BeanItemContainer or to write your own Container that knows how to access property-values inside the EObject. Then cells should show values properly.

      If you have any questions, you are welcome.

      Best, Florian

  3. Tom Schindl Says:

    Why did you go with the old and deprecated *Observeables-Factories – I think you should have only implemented the new *Properties-Factories and not even providing a VaadinObservables factory

    • Florian Pirchner Says:

      Hey tom,
      I implemented both. The observable delegates to the properties. I implemented vaadin databinding about 1.5 years ago. So there are no generics right now too. in this version the observables did not have been deprecated. At least I do not get a warning.

      and thanks for the hint. Will migrate to latest db version with generics in a few month. Then I will follow your idea.

      Thanks flo

      • Florian Pirchner Says:

        And i will add samples for the properties factory too in this blog. For each sample I am adding an additional one by properties marked as best practice.
        and will mark the other samples as “deprecated soon”.

  4. Michael Says:

    Thanks Florian. I have the same “issue” that the table does not show any property values. So i thought you have done a solution ;), so i think i would try a own container.

Leave a comment