The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


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 >> Open JDK      
Comments
Comments are listed in date ascending order (oldest first)