 |
Mixing property language support and bean bindings
Posted by forax on September 24, 2007 at 03:14 PM | Comments (21)
Recently, Shannon posts version 1.0 of beanbindings, even
if this version is not ready for production use,
it is stable enough to create a small demo mixing
property language support and
beanbindings.
The idea is to create a bean (here MyBean) with a bound
property (label) and to bind this property to two different
textfields.
Defining a bean
Because i use the property support directly integrated in the language,
defining such bean is easy. AbstractBean provides the
basic support for managing property change listeners.
public static class MyBean extends AbstractBean {
property String label bound;
private <B,T> void propertyChanged(java.lang.Property<B,T> property,Object oldValue,Object newValue) {
firePropertyChange(property,oldValue,newValue);
}
@Override
public String toString() {
return "label "+label;
}
}
Wrap the property to someting understandable
By default bean bindings only supports two kinds of property
bean property that uses bean introspector and
EL property that uses EL script but
the framework is easily extensible and let you create
your own property implementation.
So i've created a new kind of property (here LangProperty)
that exposes a java.lang.Property as a property understandable
by the bindings framework.
And mix
And now mixing the language support and
the API together is as simple as that:
LangProperty<MyBean,String> labelProperty =
LangProperty.create(MyBean#label);
JLabel label = new JLabel("Label:");
JTextField field = new JTextField(20);
Bindings.createAutoBinding(READ_WRITE,
bean, labelProperty,
field, BeanProperty.create("text")).bind();
JLabel anotherLabel = new JLabel("Another label:");
JTextField anotherField = new JTextField(20);
Bindings.createAutoBinding(READ_WRITE,
bean, labelProperty,
anotherField, BeanProperty.create("text")).bind();
The notation sharp ('#') is used to get an objet
typed java.lang.Property that allow to get and set
the value of the property.
Want to test it
You want to test it by yourself, ok, here a zip containing
the code, the beanbindings jar and the javac.jar patched to
understand properties.
Download properties-meets-bindings.zip
Use this line to compile
java -Xbootclasspath/p:javac.jar com.sun.tools.javac.Main -XDallowProperty -cp beansbinding-1.0.jar *.java
And this one to execute
java -Xbootclasspath/p:javac.jar -cp .:beansbinding-1.0.jar Sample
You must include javac.jar at runtime only because it
contains the class java.lang.Property
and i am too lazy to create two jars.
WARNING, i have re-written the bound property support in the patched
compiler last night so i think it will not work
on another example :)
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
-
this is great, there was a group of people on the binding spec (including myself) which asked, "what happens if we introduce properties in Java SE 7?" It's good to see Shannon's re-work accommodating this solution. Ideally, I would've liked to see the onus of bindings being intrinsic to the UI components, but that's a bit of a change beyond the scope of the JSR.
Posted by: jhook on September 24, 2007 at 08:28 PM
-
Hi jacob, one requirement of the property spec is to be able to
retrofit awt/swing components to use property.
If this work is done and if some helper methods are added
to Component. We end with a more concice syntax
which i think cover 80% of the use cases:
MyBean bean=...
JTextField field = new JTextField(20);
field.createAutoBinding(JTextComponent#text,
bean,MyBean#label).bind();
Rémi
Posted by: forax on September 25, 2007 at 12:54 AM
-
Remi,
I don't mean any offense and I'm trying to ask an honest question because I'm just stumped by this post (and other discussions on the subject).
I mean no disrespect, but I can't see a single advantage of this approach over existing approaches and I can see quite a few disadvantage in overhead (memory/speed), type safety/compiler checks etc... This approach is neither compatible with existing beans nor is it short in syntax (it even has arguably more cumbersome syntax) than the bean-properties equivalent which works now on Java 5....
I'm not trying to be a jerk here but can you please highlight a single advantage besides the fact that this is on its way to becoming a JSR?
Posted by: vprise on September 25, 2007 at 02:02 AM
-
Overheads ??
If you use bean approach, you use an introspector with a
cache that relies on reflection that in order to be effective
generates at runtime a specific byte-code.
I use the compiler to generate that specifc byte-code.
So there is no memory overhead, perhaps just a small
one because the generated byte-code is a bit larger
About the speed, comparing to reflection, i create less object
have neither security checks nor boxing, array wrapping, etc.
there is a clear gain here.
syntax is shorter and above all more readable
that the current way to create a property:
public static class MyBean extends AbstractBean {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String newLabel {
String oldLabel=this.label;
this.label=newLabel;
firePropertyChange(property,oldLabel,newLabel);
}
@Override
public String toString() {
return "label "+label;
}
}
About the fact that property spec to use # (sharp), if you have an idea to
remove it, i'am open.
Futhermore, the implementation is fully backward compatible with the
bean spec. I don't follow you on that point ?
You can use an introspector on an object that use property.
Do you have a specific use case ?
Rémi
Posted by: forax on September 25, 2007 at 03:35 AM
-
"....property support directly integrated in the language..."
If you need to subclass AbstractBean, then I would argue property suppert is not in the language, its in the API. Oh well, semantics. ;)
Anyway, I am torn about the bennefit of BeansBinding. In a recent project I abandoned BeansBinding over old-fashined listeners for a variety of reasons.
For instance, I had the problem that an event is only fired if the new value is different than the old value. This means, that you can not rely on setXxx methods in the constructor to do initialization unless you know specifically that the field value is different that what you are assigning.
I'm still rooting for native support of properties and events in Java, it would simplify things so much and make the Java world more consistant.
Posted by: mrmorris on September 25, 2007 at 04:27 AM
-
The overhead I was talking about is for String lookups for the binding not the "properties" which are POJO's, the current implementation of bean properties uses reflection but can use instrumentation if I wanted to make a language level change (like you did or instrumentation work). The theoretical overhead of bean properties when features such as binding/observability/ORM are involved is considerably lower since you don't need String lookup/hashing and can invoke a method directly. Obviously properties are not very helpful without these features.
I was comparing the binding related syntax to the bean properties syntax examples of which are plenty in the web site. Furthermore, the current bean properties syntax can be made even more concise using a language change approach.
About the # syntax, we have our differences but I was referring to this code:
Bindings.createAutoBinding(READ_WRITE,
bean, labelProperty,
field, BeanProperty.create("text")).bind();
Which essentially means everything needs to degrade to a string eventually for "backwards compatibility" despite not being backwards compatible.
On backwards compatibility: you can't use this without a special compiler or Java 7, where bean-properties work unmodified in Java 5. Theoretically you would be able to maintain your compiler to perform backports but from experience Java (at least 5) won't allow the source level to be lower than the target argument... This essentially means that the bean won't be backwards compatible reasonably.
Posted by: vprise on September 25, 2007 at 04:42 AM
-
@mrmorris, AbstractBean is not a part of the property API,
if you have a bound property the compiler only requires a
method propertyChanged.
You are right, there is a problem when you want to initialize
a property in the constructor.
The current version of the property spec says that
if you change the value of a property in the constructor,
the setter is not called, it's too dangerous because it leads to
an unsafe publication of a not fully constructed instance.
But the compiler currently doesn't respect that part
of the specification :(
@vprise, ok you don't like the way to create a binding.
So you hit the wrong guy, you should talk to shannon :)
I think the syntax to create a binding is not simple
because the binding framework want
to support several kind of properties.
Don't forget that you can specify a property using EL script.
About compatibility, you have 2 choices:
use beanbindings and bean property which requires
1.5 compiler an relies on String
use beanbindings and compiler property support which
will require the java version in which such compiler is
available (for sure not the 1.5 :) )
that ensure type safety without String/String lookup.
The code generated by the patched compiler
will never run on an already existing java platform
without some option to alterate the bootclass path
because it required the class java.lang.Property
to be present at runtime.
Rémi
Posted by: forax on September 25, 2007 at 05:41 AM
-
OK, now that we understand each other... Yes, binding is Shannon's responsibility but this post is about that and as I said properties without binding (ORM is also a binding of sort) isn't much.
So lets go back to my original question: why should someone use this? Are there advantages over bean properties?If not, then why not leverage your skills in compiler customization and leverage bean properties into the syntax modifications (or at least the concepts behind it)?
Posted by: vprise on September 25, 2007 at 05:54 AM
-
Why should someone use bindings ?
I think you can take a look to the overview of that tutorial
http://www.javalobby.org/java/forums/t17672
or this wiki.
Bean properties only provide a way to access to any properties
in a generic way by their name. It doesn't say how to keep
two properties in sync, convert them, validate them etc.
Do you suggest to have a syntax to bind properties
like JavaFX does ?
Posted by: forax on September 25, 2007 at 07:03 AM
-
Why should someone use objects?
POJO's do not live in a void they are usually built in order to integrate with something such as a persistence engine a front end UI etc... So sure you can look at your spec as something completely neutral from the actual use case most people will apply... However, I think you will agree with me that these use cases are common and important.
Assuming these use cases are important we would like them to work as best as possible. No, I'm not suggesting a language change (such as Java FX's approach of language level binding) I am suggesting that you do exactly what you did now which is:
Apply your properties solution to a common real world use case and then analyze how much your approach improves over this use case.
That is why the bean-properties project integrates ORM, UI bindings, validation etc... These elements are needed by 90% of the users of beans (otherwise just use a POJO I think there should be a distinction between the two), so we want to show how easy it is to build such infrastructure and how much the use cases are improved.
Your current properties approach relies too much on legacy concepts which just don't scale well to the more "creative" use cases. Even simple observability becomes far more cumbersome notice that this has nothing to do with your language syntax and everything to do with POJO's were never designed for this!
POJO JavaBeans were designed as simple drag and drop GUI builder components and the whole paradigm got way out of hand.
Posted by: vprise on September 25, 2007 at 07:43 AM
-
I miss some simple powerpoint slides which show me "This was hard to do without properties and is so easy with them. Look !".
For now, all I understand is that you can avoid reflection, hence a new compile check. Ok. But I find it a little short. Add some new fonctionalities like built-in change event listeners and I can understand it.
I'm sure I'm missing something here.
Posted by: nopjn on September 25, 2007 at 05:22 PM
-
I fully understand the use of properties. However I am a little sceptical on the design of the language additions. I would think of the properties as a special enumeration of each class.
E.g.: MyBean.properties.label (where 'properties' is an enum type)
Posted by: montechristos on September 27, 2007 at 01:05 AM
-
@vprise, use cases are important. The use case number one
is a very simple one, i want to access/modify a property
and be able to change its implementation without refactoring
nor recompilation.
i don't think observability is simple, there are several
ways to observe a property depending if you want create
an event, reuse it,
send some information or not. That why current property spec let
the user write its own method firePropertyChanged.
@nopjn, sorry i haven't this kind of slides yet but you can read my old
blog entries. i hope it will convince you that properties as language
feature are really usefull.
@montechristos, yes properties share some commons with enums
but enum value are ordered and typed by the enum class,
properties are not ordered and must surface its type.
Rémi
Posted by: forax on September 27, 2007 at 01:35 AM
-
@vprise, nopjn: Just yesterday I had to refactor a central business object of a heavy app (> 100 kloc). I had to find all usages of a certain property. With an IDE at hands, it was easy to check all dependencies and usages of this property within the Java code. But then I had to check all UI bindings, in which the property is encoded as string, and then I had to check all JPA queries containing the property, again as string. Guess what, unfortunately the property was called "name"... I really think we should get rid of strings identifying properties!
Posted by: scotty69 on September 27, 2007 at 05:17 AM
-
@Remi, I don't understand how the use case of access/modify a property relates to your current properties suggestion?
Do you mean reference existing get/set combos with the "." or "#" modifier such as bean.property even when the property keyword was not used?
Observability is trivial once you view properties as objects, once you accept that idea lots of things become much simpler. The ideas of meta-data associated with the property and the fact that a user can customize this meta-data (which is not possible with Class) is a remarkably powerful tool.
@scotty69, avoiding Strings is the main benefit I list for bean-properties in the faq ;-)
Refactoring bean-properties is a joy.
Posted by: vprise on September 27, 2007 at 11:10 AM
-
@Remi, Couldn't the type be a parameter of the enum? Also in case of collections another parameter could specify the type of contained objects? Also, this enum could extend an interface common to all the properties of all the classes. (I have developed such a construct not so long ago).
Posted by: montechristos on September 27, 2007 at 12:50 PM
-
@vprise, why do you need getter/setter ?
metadata in Java => Annotation. So java.lang.annotation.ElementType
should be augmented and java.lang.Property should implement
java.lang.reflect.AnnotedElement.
I don't want to embed a code with properties, only metadata
and because properties are observables, you can retrieve those
metadata in method propertyChanged.
@montechristos, no. Example:
class A {
property int a;
property double b;
}
A#a is a Property<A,Integer> and
A#b is a Property<A,Double>.
There is no way to do that with enum value.
Posted by: forax on September 28, 2007 at 01:19 AM
-
I would argue that annotations are a meta-data system for compile time, since some meta-data can mutate and some meta-data doesn't fit the declarative paradigm (assuming all the current problems in annotations are fixable which I don't think they are)...
Meta-data in bean-properties is user customizable which is remarkably powerful, in order to integrate ORM we can extend the meta data objects (BeanContext and PropertyContext) and add ORM specific information into these elements. Why is this important?
Because during compiler time you don't know basic things like table name etc... regarding ORM, we can hint a default using annotations (which we do) but the only other alternative is to load state from XML (which is how Java EE works: hints from annotation and deployment overriding with XML DD). So Java EE essentially contains a meta-data location in parallel to annotations which is only exposed to the user via XML (the deployment descriptor). Bean-properties allow you to programmatically customize meta-data which has huge advantages in terms of compiler checks e.g. we can declare a relation between two properties programmatically and this is verified by the compiler. Since annotations currently don't allow pointers (see my comment above about annotations) this is impossible to do with them.
These examples are valid for ORM, but customizable meta-data is critical for localization (JSR 295 uses or used property names for table columns!), validation etc... You can say that this is not a part of a property spec and you would be right... But a property specification should be designed with thought about enabling these features which current properties can't possibly enable (without making java.lang.Class/java.lang.annotation.ElementType implode).
Posted by: vprise on September 28, 2007 at 07:51 AM
-
@Remi. I am suggesting this, but it should not be explicit. I see it as an implicit enum called 'properties'.
class A {
int a;
double b;
ArrayList l;
enum properties implements Property {
a(A.class, Integer.class);
b(A.class, Double.class);
l(A.class, ArrayList.class, String.class);
}
}
Posted by: montechristos on September 29, 2007 at 06:58 AM
-
The formating took out the ArrayList of String
Posted by: montechristos on September 29, 2007 at 07:01 AM
-
Apart from the syntax of the Properties, I would like to ask:
1) Could one iterate over the Properties of a class?
2) Could you get the Field from the Property?
3) Could you get the Property from the field?
Posted by: montechristos on September 29, 2007 at 07:08 AM
|