 |
Beansbinding goes to the wrong direction
Posted by forax on June 23, 2007 at 02:33 PM | Comments (24)
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:
- 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.
- 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.
- they can manage conversions
(by example between text and primitive type,
date etc) because a bean property exports its type.
- 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:
- 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.
- 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.
- 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.
- 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.
- 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.
- there is no way to set a collection of possible conversions
for a group of bindings.
- 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.
- 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.
- 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
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Properties, bindings and a better component model are all connected. If Sun creates islands of solutions without solving all these three things at the same time the solution will not only be bad but also feel outdated and suboptimal when the other solutions are eventually rolled in.
I wish that they stopped this EL madness now and take a real stab at the core problem instead. Add real properties, with type safe bindings included, and with that in place propose a new or better component model through the slumbering JSR 273. It's IMHO the only way that the very non-thriving component market for Java is going to take off.
Posted by: mikaelgrev on June 23, 2007 at 03:01 PM
-
Indeed, using annotations an EL seems to be a growing trend in Java to work around its limitations. For instance, in EJB3/JPA where we are starting to get a language within a language which will only validate at runtime.
I think we need to lower the abstraction barrier and get properties/event binding into the language (not XML, not EL but Java) rather than relying on observable interfaces, naming patterns, BeanInfo metadata, generated adapters etc.
Sadly, I don't think many Java developers have even looked at (D)LINQ and it would also be hard to implement given Java's generics erasure semantics.
Posted by: mrmorris on June 23, 2007 at 03:18 PM
-
"a language which will only validate at runtime", if validation at runtime means something.
Rémi
Posted by: forax on June 23, 2007 at 03:41 PM
-
Valid in this regard meaning, binding context valid. A concrete example if you use BeansBinding but with something invalid in the EL and get a a "java.lang.IllegalArgumentException: no property named Blahblah in BlahBlah" when you try to launch the application.
Posted by: mrmorris on June 23, 2007 at 04:05 PM
-
Yes, but the opposite is not true, because you bind business objects,
your application may work until a user insert specific value.
So the only fact that you "validate" when you run your program is
that it work on your data.
Rémi
Posted by: forax on June 23, 2007 at 05:03 PM
-
I've submitted some patches that are consistent with these goals:
https://beansbinding.dev.java.net/servlets/ReadMsg?list=dev&msgNo=1
https://beansbinding.dev.java.net/servlets/ReadMsg?list=dev&msgNo=2
Your ideas are appreciated. Stay tuned - Beansbinding is a work in progress!
Posted by: jessewilson on June 23, 2007 at 05:06 PM
-
i'm on the EG and wasn't happy with the current solution either. I kept pushing the concept of a binding to just be a contract such that you could have an ELBinding, or any other type of Binding instance working together. The main point was, 'What if SE 7 introduces properties, where's the API going to be?". We are already able to handle chained Binding or 'ValueExpression' instances within JSF, so I wasn't sure why Sun's draft went with such a literal contract in the proposed API. Now, there are benefits to allowing EL use for binding such that you can disconnect state from the UI and you can plug-in flexible resolution (custom ELResolvers or syntax), but, the proposed API buries that functionality too.
Posted by: jhook on June 24, 2007 at 07:51 AM
-
jhook, I have yet to see an explanation why Sun are creating a solution that isn't extensible to make sense in a situation where we have properties and a better JavaBean spec. EL should be an option and not the base technology.
As one of very few GUI component vendors in the Java scene I must say that patience is running out. I seems that the wrong people are in the wrong places somehow because even though the intentions are good, and the developers are great, everything always seem to miss the important last piece of the puzzle. The base problem seem to be that the timing is always off and every solution is forced out the door with the words: "We need this NOW!".
Posted by: mikaelgrev on June 24, 2007 at 02:24 PM
-
Fully agree with mikaelgrev and mrmorris: Any EL-based binding is a dead-end. The LINQ-approach is lightyears ahead. Sadly to see how things go wrong.
Posted by: scotty69 on June 24, 2007 at 02:40 PM
-
Bruce Eckel actually had the guts to mention LINQ at the Java posse open spaces conference, it just became silent for a few seconds and people acknowledged that nobody followed .NET because its "just a copy of Java anyway" whereto Eckel replied "...well they are doing some awfully interesting stuff".
And again the other day, he referenced it indirectly on his blog:
"Flex was designed with user interfaces at the forefront, so it includes true properties and events as well as "data binding" to automatically move data from one place to another when something changes. It's unfortunate features like this never made it into Java."
My hat off to him, but if he can't get the message across then I doubt anyone can.
Posted by: mrmorris on June 24, 2007 at 08:12 PM
-
don't you think that if we were able to get proper properties into Java 7 or more generally, # syntax for metadata, that it would lick a lot of the binding/event/callback issues from a gui standpoint and otherwise? I just don't get why people are dragging their feet about adding this functionality.
Posted by: jhook on June 25, 2007 at 08:33 AM
-
"Any EL-based binding is a dead-end"
Yes, I also agree. I do not accept that there is no other way besides embedding a scripting language.
Posted by: aberrant on June 25, 2007 at 10:21 AM
-
Hi Rémi! You've made many valid points here and they are things that I will fully consider. At the moment, I'd like to address three of them:
Issue 1: Support for binding to custom components with special listeners is provided by allowing you to resgister a PropertyDelegateProvider.
Issue 6: Setting a group of BindingConverters on a group of bindings is something that's already planned.
Issue 9: While there is no support for a dynamic bean like you've mentioned, you can certainly bind to a Map. Do you have suggestions on how we can support dynamic beans?
Thanks!
Posted by: shan_man on June 25, 2007 at 11:56 AM
-
jhook about the objection to property syntax there are several issues:
The main problem is that current proposals are a thin layer on top of get/set, in order to use the # syntax as a pointer there are two options:
The compiler translates property name to a string - all the same problems from before exist but now they are automated by the compiler.
Compiler creates a Property object on the fly - memory nightmare and no ability to track property specific state.
About the syntax be it pound arrow or dot people will argue forever (so would I), there is no point in getting into that.
Generally the statefull approach for properties is my personal preference and other than syntactical complaints I have yet to see a single person who actually read the information about the project provide a single significant drawback to this approach. I implemented it at https://bean-properties.dev.java.net/
Posted by: vprise on June 25, 2007 at 12:45 PM
-
in reply, the property object on the fly as being a memory nightmare? i'm aware of the weak reference vs. strong reference issues but nothing that isn't solvable-- or at least committing to one approach. I'd love to see something like you've presented, except handle it natively with a property keyword or something similar to C#. While I don't want to start another properties discussion, remi's pretty much whacked it, I'm just saying Java should commit to a language-level solution.
Posted by: jhook on June 25, 2007 at 06:10 PM
-
"Java should commit to a language-level solution."
Agree 100%. Unfortunately it seems as though legacy code compatibility is winning and I suspect when we finally do get properties in Java, it will merely be a compiler hack (much like inner classes and generics) using @Get and @Set annotations. But hopefully then someone will do a fork.
Posted by: mrmorris on June 25, 2007 at 06:47 PM
-
One more vote against expression languages solving Java's problem. This is something I also feel the language needs augmentation for. PLEASE don't dissolve Java into strings...
Posted by: ilazarte on June 25, 2007 at 08:47 PM
-
Property objects on the fly would require a new object to be created every time you reference a property with the # lookup. For the most common use case of binding listeners people often think of this as a one time thing, but it isn't and it gets far more complicated than this.
In binding implementations and while using them you sometimes have to bind and unbind data on the fly. This would create large amounts of redundant garbage. Furthermore, the main and real problem is that you can't do this: b#p == b#p. This is a huge problem since often you need to distinguish properties, the equals method should work on the content of the property unlike ==.
Besides if weak references were so great then remove listener would have been deprecated ;-)
Posted by: vprise on June 25, 2007 at 09:07 PM
-
Let's keep simple and easy. Hans muller and Remi Forax blogs on describing properties in java with annotations or creating new key words on java langage; and now we talk about binding and EL. All of this, isn't it tricks ? I think we all have the feeling that we are missing anything to have a better structure on communication and relations in order to modelize more complex things, like systems. Maybe let's look at how cybernetics sciences modelize the world and it's communications problems and we could give a true evolution to java modelization force, and simplicity. Just a question: is a mix beetween mediator & observator pattern - scripting langage... a solution to manage communication between systema ? or just beetween the GUI layer and it's presentation data model ?
Posted by: alec6 on June 26, 2007 at 02:08 AM
-
vprise, i know how to solve the identity problem (==),
i think it was first suggested by stephen colebourne.
You can apply sharp ('#') on a class and on an instance but
it doesn't create the same object.
On a class, Author#name is a java.lang.Property object whith ==
semantic and its methods get/set take an instance argument.
On an instance, author#name is a java.lang.reflect.PropertyInstance
object, which is a short live object with equals semantic that
contains a reference to a path of Property objects (you can
write a#hello#world) and an instance of the bean class.
So you can't write b#p == b#p safely, but you can write B#p == B#p.
Rémi
Posted by: forax on June 26, 2007 at 02:11 AM
-
Rémi, thats an interesting solution fitting of Stephen ;-)
In fact I hope that if an object based solution would be adopted then BeanContext would be accessible through java.lang.Class in much the same way.
I don't want to get into this discussion though (I'm just glad we agree that a context is important), at least some of this discussion is around the notion of 295 working with todays code and not waiting for Java 7.
Posted by: vprise on June 26, 2007 at 09:33 AM
-
Thanks for the note on bean#property syntax! I'm intriuged about what you believe that a#b#c should do - its not something I've thought about before (other than disallowing it).
Posted by: scolebourne on June 29, 2007 at 02:36 PM
-
The lazy scripting (Web2.0) fans need to get it through their thick heads that most linkage should be type-safe and checkable outside a runtime environment. It really annoys me that Sun et-al are still dragging their heals over the following:
* proper first class Functions in classes.
* proper compiler checked Method and property references for classes and objects.
I have a framework which has to use reflection to make hard coded transformation proxies for sets of named properties and methods, but I have to include bulky runtime construction error trapping because Java lacks proper type-safe property and method references!
It seems so pointless having to abuse reflection when type-safeness should not be hard to do. Sun and associates need to be far more pragmatic and make smarter compilers to support proper type-safe meta-references, with none of these erasure excuses, then we could do away with most of the need for scripting and text references outside of web-pages.
Erasure is seems a quite bogus, lazy and unnecessary idea which just causes pain, the compiler and JVM should do the magic, the method and property methods should contain generics type hints, possibly code paths for legacy use, either in the class or added by the class loader. The JVM could use the hints to spot legacy data/requests and use legacy code paths for these.
Posted by: infernoz on July 08, 2007 at 05:32 AM
-
Yes, I also agree. I do not accept that there is no other way besides embedding a scripting language.
Posted by: winrelocation on October 30, 2007 at 01:06 AM
|