Skip to main content

Beansbinding goes to the wrong direction

Posted by forax on June 23, 2007 at 2:33 PM PDT

Shannon Hickey recently post a blog entry about
a new release of Beans Binding project at
http://beansbinding.dev.java.net


I have take a look to the documentation and my first belief is
that the API doesn't guide the user enough.


But let me first introduce the concept of bindings.

What is a binding ?

A binding is a two-way connection between two
properties (javabean property). When you change the value of one,
automatically the value of the other one is changed.


The concept is not new, i have used JGoodies binding
two years ago and the framework was mature at that time.
And this concept is heavily used in web tier like Tapestry,
JSF etc.

Why do we need bindings ?

Bindings are very elegant solution when you want to
cleanly separate the presentation logic
to the presentation view of a form.


The presentation view is a panel or a dialog with
its components and the presentation logic is a bean.
A binding allows you to connect a component
(textfield, combo, etc) property
to its corresponding bean's property.


So by example if you decide to change a textfield by a combo,
you only update the presentation view, and doesn't change
the presentation logic.

Furthermore bindings are great because:

  1. it provides a unified concept that hide the complexity
    of dealing with different swing listeners,
    by example, the selected value of a list is not a bound
    property, a textfield can't be changed when it
    fire a modification event, etc.

  2. if you set a validator to a binding,
    you can do validation (on the fly), and provide a feedback
    to the user by changing the component visual aspect.
    Futhermore if you have a way to
    group bindings you can easily find the list of all unvalidated bindings.

  3. they can manage conversions
    (by example between text and primitive type,
    date etc) because a bean property exports its type.

  4. dealing with swing listeners often leads to memory leaks,
    with a binding you can easily remove listeners by unbinding it or
    better by unbinding a group of bindings.

If you want more info, take a look to an introduction to
jgoodies binding
by R.J. Lorimer.

Simplifying the MVC

beansbinding spec/implementation allow not only to
define bindings between simple components but
to define bindings on MVC components like JList, JTable, JTree,
i.e on components that display multiple objects.
This provide a more simpler way to define component's model.

Let me take an example, i have a list of employees and i want
to display their names in a JList.
Moreover, if i modify the employee list or if i change the name of one
employee, i want the JList to reflect that change.


A JList (like JTree or JTable) has 3 kinds of events,
added, removed or changed. So my list need to be able to
signal addition or removal and employee objet need to
signal when its name changed.


Employee name modification is signaled using a classical binding

  List list=...
  new Binding(list, null, "${name}");

Furthermore beanbindings introduces the concept of ObservableList which
is a List with listeners that report additions and removals.
It is not new, glazed list already have the same concept,
but its is the first time i see the two concepts merged.

Why do we need the Expression Language ?

beansbinding let you specify the bound property
using a enhanced version of the Expression Language (EL)
script already use in JSP or JSF.


Suppose that now i want to display the list of street name of
my employee. I can create this kind of binding

  List list=...
  new Binding(list, null, "${address.streetname}");

EL is used here to indicate the path to the property
and all properties along that path are listened.
You need to do that because if the address is changed
the street name may changed too.

So if binding are is a great concept why don't you like beansbinding ?

I just don't like some parts of the current implementation of bean bindings:

  1. javax.beans.binding.Binding is not an abstract class,
    so it's not a concept. I can't create a binding
    on a user defined component that have a specific listener.

  2. beansbinding allows to define a tree of binding but i think
    it's not necessary, a path of bindings
    (or a collection/map of binding path) is sufficient.

  3. you can define a binding and forget it, this will lead
    to memory leaks,
    All bindings need to appear in a group of bindings to be
    unbound easily.

  4. name a binding (new in 0.6) is not a good solution(tm),
    an object is always more powerfull than a string,
    if you want a reference to a binding, store it
    in a field.

  5. there is no simple way to get the list of bindings that
    have validation errors.
    Furthermore, pratically convertions and validations
    are often the same operation in Java,
    by example there is no method Integer.isAnInteger(),
    Integer.parseInt() do the convertion
    or throw an exception.

  6. there is no way to set a collection of possible conversions
    for a group of bindings.

  7. beanbindings use EL script so goodbye type safety.
    There is a real risk of creating a desktop applications
    that will work or not depending on inputs (by example, of
    data of a database)
    Java really needs something like C# expression trees,
    a part of (D)LINQ.

  8. the way to define bindings for MVC component is clumsy,
    by example you can set the parameter of a tree to
    a binding that bind a table.

  9. there is no support for dynamic bean. Roughtly,
    a dynamic bean is a hashmap of String/value with
    a property change listener mecanism.
    Swing's AbstractAction is that kind of bean,
    so there is currently no way to bind the name of an
    action to a text of a textfield.

Proposed new Design

Ok, i ve tried to summarize all my remarks in a new design:

  public abstract class Binding {
    Object getSource();
    Object getTarget();
    Binding setValidator(Validator validator);
    void bind();
    void unbind();
    //etc...
  }

  //BindingContext renamed
  public class BindingGroup {
    List bindingList() {...}
    void bindAll() {...}
    void unbindAll() {...}
    // list of all bindings that are not validated
    List unvalidatedBindingList() {..}
    void addValidationListener(ValidationListener l) {...}
    void removeValidationListener(ValidationListener l) {...}
    // the mapper find a converter by its source and target types
    void setConverterMapper(ConverterMapper mapper)
  }

  public interface ValidationListener extends java.util.EventListener {
     void validationFailed(Binding binding, ValidationResult result);
     // allows to remove visual effect on component
     void validationOk(Binding binding);
  }

  // i have tried to separate bindingroup concept from
  // the binding factory, not sure that is a good idea
  public class BeanBinder {
    public BeanBinder(BindingGroup group) {...}
    public BeanBinder() { this(new BindingGroup()); }
    public BindingGroup getBindingGroup() {...}
    public Binding addBinding(Object source,String sourceExpr,Object target,Object targetPath) {...}
  }
 
  // add swing bindings for some specific components
  public class SwingBinder extends BeanBinder {
    public Binding addSelectedBinding(JTextCompmonent text, Object target,Object targetPath) {...}
    public Binding addSelectedBinding(AbstractButton button, Object target,Object targetPath) {...}
    public Binding addBinding(AbstractAction action String sourceExpr, Object target,Object targetPath) {...}
    public Binding addSelectedBinding(JList list, Object target,Object targetPath) {...}
    //etc.

    ListBinding addListBinding(JList list, ObservableList list) {...}
    ListBinding addListBinding(JList list, Object source, String sourceExpr) {...}

    TableBinding addTableBinding(JTable table, ObservableList list) {...}
    TableBinding addTableBinding(JTable table, Object source, String sourceExpr)
{...}   
    TreeBinding addTreeBinding(JTree tree, Object root) {...}
    //etc. 
  }
 
  // list specific binding
  abstract class ListBinding extends Binding {
    JList getSource() {...}
    ListModel getModel() {...}
    Binding addElementBinding(String elementPath) {...}
  }

  abstract class TableBinding extends Binding {
    JTable getSource() {...}
    TableModel getModel() {...}
    Binding addColumnBinding(int index,String elementPath) {...}
  }

  abstract class TreeBinding extends Binding {
    JTree getSource() {...}
    TreeModel getModel() {...}
    Binding addNodeBinding(Class nodeClass,String elementPath) {...}
  }

What do you think about that ? i wait your answers.

Cheers,

Rémi

Related Topics >>