Tuesday, August 7, 2007

Eclipse data binding with java beans

I’ve been thinking about how to provide easiest tutorial on data binding allowing you to go through all steps smoothly. I was thinking and coding and it is a little bit more complex than I planned ;)


Since code was ready couple of things has changed so I need to check if all dependencies in this project are needed. I’ll will show you a standalone application example but to make things easier (in my opinion) let me start from plug-in project. This will allow us (if we are building on Eclipse 3.3) to add all needed libraries from our Eclipse distribution.


This will be example of bidirectional synchronization between Java Bean and simple form which presents bean’s content. So let’s start.


Build java bean class.


This can be something simple (I will take a Address class with two fields street and city)


Defining an user interface


To build a screen in an automatic way we will use java.beans.Introspector. But let start from beginning. We must add dependencies to JFace library to our build path. As our project is plug-in project it can be done as adding dependency to JFace.



To build fields for our bean’s properties we can use following code fragment:

BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(bean.getClass());
} catch (IntrospectionException e) {
e.printStackTrace();
return;
}
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor descriptor : propertyDescriptors) {
if("class".equals(descriptor.getName())) continue;
Label label = new Label(shell, SWT.NONE);
label.setText(descriptor.getName());
Text t = new Text(shell, SWT.BORDER);
//here will be data binding added
}


Rest of source code can be found in attached project file. After running application (as Java application) this should look very similar to :



Adding data binding (from UI to bean)



Now there is a high time to add data binding to our simple application.
Add core binding, jface and bean bindings (org.eclipse.core.databinding, org.eclipse.core.databinding.beans, org.eclipse.jface.databinding). This will allow us to connect Text components with its data model (which is our address bean).


We need to create binding context and realm:

Realm realm = SWTObservables.getRealm(shell.getDisplay());
DataBindingContext bindingContext = new DataBindingContext(realm);

Using bindContext we are able to connect our text components with data:

private void bindValue(DataBindingContext context, Text text, String name) {
IObservableValue observeValue = BeansObservables.observeValue(context.getValidationRealm(), bean, name);
ISWTObservableValue observeText = SWTObservables.observeText(text, SWT.Modify);
context.bindValue(observeText, observeValue, null, null);
}



But when we try to run this application you will get a unresolved dependencies (NoClassDeffinitionFound exception). We need to add additional dependencies to our project (org.eclipse.core.runtime).
If you followed this article you should get something similar to:


We have one another feature for free now. If you change name of the street or city this changes from our simple windows are applied to data object. Let’s try to add opposite direction data shifting.


Adding data binding (from bean to UI)



To make our data object to be source of changes we must implement basic property change support.

abstract class AbstractModelObject {
public void addPropertyChangeListener(PropertyChangeListener listener);
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener);
protected void firePropertyChange(String propertyName, Object oldValue,
Object newValue);
}

And let our AddressBean class extends AbstractModelObject. The only think we must remember is to add firePropertyChange for each set method.
One again we win twice. First of all we can add change listener to our data object. Second we have bidirectional data synchronization between our graphic and data component.


Fun, fun, fun



The only last step to show power of data binding is adding a thread which will update data object. All this changes are visible in our simple control.
Adding other type of field is a piece of cake. First we need com.ibm.icu in our dependencies. Second adding field of other type (e.g. int or data).


Hope this article will help you to start your journey through Eclipse data binding features. Article source code can be found here
The final result is following:

2 comments:

Boris Bokowski said...

Thanks for writing this! How about turning this into a wiki page?

Note that instead of org.eclipse.core.runtime, it is sufficient to add a dependency on org.eclipse.equinox.common, which is much smaller.

Also, if you don't want to add the whole ICU4J, you can find the replacement plug-in com.ibm.icu.base on the download page for any Eclipse project build >=3.2.

Darwin Baisa said...

Hi,

I am planning to develop a configuration tool using SWT/JFace and jface databinding. Is this a right choice or should i go for Swing only?