 |
Community: Java Specification Requests Archives
Beans Binding 1.1.1 Beats 1.0's Butt, Bigtime
Posted by shan_man on October 19, 2007 at 01:08 PM | Permalink
| Comments (12)
I'm pleased to announced that version 1.1.1 of Beans Binding has just been released
at http://beansbinding.dev.java.net/.
This release provides a drastic increase in performance over 1.0,
the addition of support for binding to a JSpinner's
value property, and a small set of bug fixes.
Extreme performance gains in this release are the result of a fix made to
the BeanProperty and ELProperty classes. As these
classes are central to Beans Binding, most things now perform many orders
of magnitude faster. Consider the following simple test case, that fetches
the value of a property 100,000 times for the same object:
Person person = new Person("John", "Smith");
Property p = BeanProperty.create("firstName");
p.addPropertyStateListener(person, new PSL());
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
p.getValue(person);
}
System.out.println(System.currentTimeMillis() - start);
In 1.0, this test takes approximately 13,000 milliseconds on my machine.
On the contrary, it takes approximately 8 milliseconds in 1.1.1.
How's that for bigtime?! You can imagine how applications with many
bindings, or components like JTable and JList with
large data sets, will perform much better with this version.
I imagine some of you are curious as to how this incredible change in performance
was possible. As described in the JavaDoc for BeanProperty and
ELProperty, once a listener is installed on the property, values
along the paths are cached, and only updated in respose to property change
notifications. Knowing that developers are likely to encounter beans
that don't fire the correct notifications, and that resulting problems
may pose tricky to debug, I began work on allowing developers to turn on a debug
option that would have BeanProperty and ELProperty log
a message when they detect such a change without notification. They would do this
by re-evaluating the entire path on every method call and comparing each object
to what they have in their cache. This would, of course, remove any performance
gains accomplished by the caching; but only when the debug option is on.
While the toggle for this debug option hasn't yet been added, it turns out that
in 1.0 the logic itself was left turned on, only without the messaging—a code path
that served only to remove all caching benefits. In 1.1.1 this code path has been
turned off pending completion of the debugging feature.
And since we're talking about performance, I'd like to share something else
with those of you looking to get every last drop of speed from the current
implementation. Naturally you'd expect BeanProperty to perform better
than ELProperty for simple paths, since the former avoids the overhead of EL
parsing. This will, of course, be true once the implementation has been
further optimized. In the current release, however, ELProperty actually
performs better in many cases. Consider the following test case that creates
a new BeanProperty 100,000 times, and uses each instance to fetch
the value for a new object:
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
Property p = BeanProperty.create("firstName");
p.getValue(new Person("John", "Smith"));
}
System.out.println(System.currentTimeMillis() - start);
This test dramatizes the case of an application that creates and binds a large set
of bindings, with similar properties, perhaps on the first initializion of a GUI
form. In 1.1.1, this code takes approximately 7000 milliseconds on my machine. But
replacing BeanProperty with ELProperty reduces it to 330
milliseconds.
Consider this similar test case that uses a single BeanProperty and
fetches its value for 100,000 new objects:
long start = System.currentTimeMillis();
Property p = BeanProperty.create("firstName");
for (int i = 0; i < 100000; i++) {
p.getValue(new Person("John", "Smith"));
}
System.out.println(System.currentTimeMillis() - start);
This test dramatizes what JTable or JList might have to do while
scrolling, to fetch the value of a single property for a large set of objects. In 1.1.1,
this test takes approximately 6900 milliseconds on my machine. Replacing
BeanProperty with ELProperty reduces it to 260 milliseconds.
I raise this discussion as a point of interest, not to encourage you to switch to
ELProperty (unless your application demands the performance increase that it
currently brings). As I mentioned, BeanProperty will be optimized to be the
better choice for simple paths. Profiling indicates that the source of ELProperty's
higher performance lies with EL's built-in caching of JavaBean BeanInfos—something
that can easily be added to BeanProperty.
One final note before I sign off for the weekend: Some of you might ask why the release number
has jumped from 1.0 to 1.1.1. The answer is that I actually first released a 1.1, and before I had
finished writing up an announcement, internal testing revealed an existing, but previously
unknown bug that I thought was worth fixing quickly. Hence 1.1.1. Enjoy!
Beans Binding 1.0 Released
Posted by shan_man on September 05, 2007 at 04:53 PM | Permalink
| Comments (59)
-- From Saint Petersburg, Russia @ 3:30 AM local time
It's finally time! After months of eating, sleeping and drinking
Beans Binding, I'm thrilled to finally announce that version 1.0 has been released at
http://beansbinding.dev.java.net
for your binding pleasure!
1.0 represents a major re-architecture of the Beans Binding API, based on the
extremely valuable feedback from members of the expert group and the community.
I'd like to say thank you to all of you who have discussed ideas with me and
contributed your own. I've tried to combine and build on these ideas and create
an API that is powerful, flexible, extensible and easy to use. I hope you'll keep
the feedback coming so we can continue this rewarding process.
While the work on this project continues through the JCP process,
with feature additions and possible API changes to come, the current
state represents the core API that is expected, for the most part, to
persist. As such, we're calling it 1.0 and releasing!
Some of the major points of interest in this release:
- The concept of a property has been factored out into an abstract
Property class,
with two concrete implementations of interest: BeanProperty and ELProperty.
Binding is now an abstract class representing a binding between two Property
instances (typically associated with two objects).
- Binding with automatic syncing is implemented by a new concrete
AutoBinding subclass.
- Bindings to complex Swing components (such as
JTable, JList and JComboBox) are
now handled by custom Binding subclasses.
- The synthetic Swing properties that offer multiple possible behaviors are now exposed
via multiple versions of the property.
For example:
"text", "text_ON_FOCUS_LOST" and "text_ON_ACTION_OR_FOCUS_LOST"
for JTextField; "selectedElement" and "selectedElement_IGNORE_ADJUSTING" for
JList and JTable.
- Everything has been repackaged into
org.jdesktop packages.
It is my hope that the JavaDoc provided with this release will have you well on your way to binding with the new API
very quickly. While I would love to take you on a tour through the entire API here, composing such a tutorial would delay
this announcement. As such, I'll present a few examples to get you started, let you get going with the new API, and then follow up
with additional blog entries, as time allows, on particulars deserving more attention. As always, please feel free to send
me your questions and/or feedback at any time.
Examples
For the purposes of these examples, we'll work on Person beans, and assume that Person
has the following properties: firstName, lastName, age and mother.
Creating and using BeanProperty and ELProperty:
// create a BeanProperty representing a bean's firstName
Property firstP = BeanProperty.create("firstName");
// create a BeanProperty representing a bean's lastName
Property lastP = BeanProperty.create("lastName");
// create a BeanProperty representing the firstName of
// a bean's mother
Property motherFirstP = BeanProperty.create("mother.firstName");
// creata an ELProperty representing a bean's mother's full name:
Property motherFullP =
ELProperty.create("${mother.firstName} ${mother.lastName}");
// create an ELProperty representing whether or not a bean's
// mother's age is greater than 65
Property motherOlderP = ELProperty.create("${mother.age > 65}");
// print Duke's first name
System.out.println(firstP.getValue(duke));
// print John's first name, reusing the same property
System.out.println(firstP.getValue(john));
// print Duke's mother's full name
System.out.println(motherFullP.getValue(duke));
// set Duke's mother's first name
motherFirstP.setValue(duke, "Jennifer");
// set John's mother's first name, reusing the same property
motherFirstP.setValue(john, "Melanie");
// listen for changes to motherOlderP for Duke
motherOlderP.addPropertyStateListener(duke, listener);
Creating AutoBindings between two properties:
// Bind Duke's first name to the text property of a Swing JTextField
BeanProperty textP = BeanProperty.create("text");
Binding binding =
Bindings.createAutoBinding(READ_WRITE, duke, firstP, textfield, textP);
binding.bind();
// Bind Duke's mother's first name to the text property of a Swing JTextField,
// specifying that the JTextField's text property only reports change
// (thereby updating the source of the READ_WRITE binding) on focus lost
BeanProperty textP = BeanProperty.create("text_ON_FOCUS_LOST");
Binding binding =
Bindings.createAutoBinding(READ_WRITE, duke, motherFirstP, textfield, textP);
binding.bind();
// Bind the motherOlderP for Duke to the selection of a display-only Swing JCheckBox
BeanProperty selectedP = BeanProperty.create("selected");
Binding binding =
Bindings.createAutoBinding(READ, duke, motherOlderP, checkBox, selectedP);
binding.bind();
Using Swing Binding subclasses:
// Bind a List of Person objects as the elements of a JTable and specify
// that columns should be shown for the beans' first name, mother's full
// name and whether or not the mother is older than 65
JTableBinding tb = SwingBindings.createJTableBinding(READ, personList, personJTable);
tb.addColumnBinding(firstP)
.setColumnName("First Name").setColumnClass(String.class);
tb.addColumnBinding(motherFullP)
.setColumnName("Mother's Full Name").setColumnClass(String.class);
tb.addColumnBinding(motherOlderP)
.setColumnName("Mother older than 65").setColumnClass(Boolean.class);
tb.bind();
// Bind the last name of the table's selected element to a JTextField
Property selectedLastP = BeanProperty.create("selectedElement.lastName");
Property textP = BeanProperty.create("text");
Binding selBinding =
Bindings.createAutoBinding(READ_WRITE, personJTable, selectedLastP,
textfield, textP);
selBinding.bind();
// Bind a List of Person objects as the elements of a JList
// and specify that the list should display the first name of the beans
JListBinding lb = SwingBindings.createJListBinding(personList, personJList);
lb.setDetailBinding(firstP);
// Bind the last name of the list's selected element to a JTextField,
// specifying that changes to the selected element are ignored while
// it is adjusting
Property selectedLastP =
BeanProperty.create("selectedElement_IGNORE_ADJUSTING.lastName");
Property textP = BeanProperty.create("text");
Binding selBinding =
Bindings.createAutoBinding(READ_WRITE, personJList, selectedLastP,
textfield, textP);
selBinding.bind();
Beans Binding 0.6.1 Release Available
Posted by shan_man on June 22, 2007 at 02:41 PM | Permalink
| Comments (6)
Taking into consideration the feedback that I've received since yesterday's blog on the 0.6 release of Beans Binding,
I've just released 0.6.1 with simpler and more intuitive method names and constants. It's available at
http://beansbinding.dev.java.net
Full details, straight from the release notes:
API Changes/Additions
UpdateStrategy.READ_FROM_SOURCE has been renamed to the shorter
UpdateStrategy.READ
TextChangeStategy is now a top-level enum. In addition, the values
CHANGE_ON_TYPE, CHANGE_ON_ACTION_OR_FOCUS_LOST
and CHANGE_ON_FOCUS_LOST
have been shortened to ON_TYPE,
ON_ACTION_OR_FOCUS_LOST, ON_FOCUS_LOST.
Binding.Parameter has been renamed to Binding.ParameterKey and
Binding.setValue/getValue have been given the more appropriate names
Binding.putParameter/getParameter.
All Swing ParameterKeys are now in a top-level ParameterKeys class.
They've been renamed as appropriate to reflect the fact that they are constants.
A few have also been shortened.
SwingBindingSupport has been removed. Documentation for Swing binding
is now in the package-level documentation.
To see how some of these changes affect you, let's look at two examples:
Before:
Binding b = new Binding(list, null, table, "elements");
b.addChildBinding("${firstName}, null)
.setValue(SwingBindingSupport.TableColumnParameter, 0)
.setValue(SwingBindingSupport.TableColumnClassParameter, String.class);
After:
Binding b = new Binding(list, null, table, "elements");
b.addChildBinding("${firstName}, null)
.putParameter(ParameterKeys.COLUMN, 0)
.putParameter(ParameterKeys.COLUMN_CLASS, String.class);
Likewise, before:
Binding b = new Binding(object, "${property}", textField, "text");
b.setValue(SwingBindingSupport.TextChangeStrategyParameter,
SwingBindingSupport.TextChangeStrategy.CHANGE_ON_TYPE);
After:
Binding b = new Binding(object, "${property}", textField, "text");
binding.putParameter(ParameterKeys.TEXT_CHANGE_STRATEGY,
TextChangeStrategy.ON_TYPE);
Beans Binding 0.6 Release Available
Posted by shan_man on June 21, 2007 at 09:04 AM | Permalink
| Comments (7)
Just a short note to announce that I've posted the 0.6 release of
the Beans Binding project at http://beansbinding.dev.java.net
In this release:
- Improved
JTable support
- More default converters
- Name your
Bindings
- Compile-time type safety for setting
Parameters
- A handful of method renames
Full details, straight from the release notes:
API Changes/Additions
Binding.addBinding/removeBinding/getBindings have been renamed to the more
descriptive Binding.addChildBinding/removeChildBinding/getChildBindings
Binding.setSourcePath/getSourcePath have been renamed to the more
appropriate Binding.setSourceExpression/getSourceExpression
To enforce compile-time type safety, the Object varargs parameter has been
removed from all constructors and methods in Binding and BindingContext.
You must now call setValue directly. To allow for method chaining, setValue
now returns the Binding. As an example, replace this binding:
Binding b = new Binding(source, "${property}", target, "property",
Parameter1, param1Value, Parameter2, param2Value);
with this:
Binding b = new Binding(source, "${property}", target, "property");
b.setValue(Parameter1, param1Value).setValue(Parameter2, param2Value);
Some Binding and BindingContext methods were updated to throw the more
appropriate IllegalArgumentException (rather than IllegalStateException)
for certain conditions.
Binding now has a name property. The ability to name a binding assists in
debugging. Its main goal, however, is to make it possible to fetch
bindings by name. This will show its full utility with future changes
making it easier to validate and then commit or revert bindings as a group.
To support naming a binding, the following API additions have been
made to Binding:
- Constructors that take a
String name parameter
void setName(String name)
String getName()
addChildBinding methods that take a String name parameter
Binding getChildBinding(String name)
In addition, the following additions have been made to BindingContext:
addBinding methods that take a String name parameter
Binding getBinding(String name)
Added a Parameter to control the editability of a JTable when it is the
target of a binding. A new EditableParameter has been added to
SwingBindingSupport to control this. It can be used on a top-level
binding to control the editability of the entire JTable, and/or on the
binding's individual child bindings to control editability of individual
columns. For example, to make all columns non-editable, except for
the first:
Binding b = new Binding(list, null, table, "elements");
// whole table is non-editable
b.setValue(SwingBindingSupport.EditableParameter, false);
b.addChildBinding("${firstName}, null)
.setValue(SwingBindingSupport.TableColumnParameter, 0)
// this column IS editable
.setValue(SwingBindingSupport.EditableParameter, true);
b.addChildBinding("${lastName}, null)
.setValue(SwingBindingSupport.TableColumnParameter, 1);
Issues Resolved
- 2: Need converters between various types and String
- 5: JTable binding support doesn't support sorting and filtering
Other
The JavaDoc in Binding and SwingBindingSupport has been updated to reflect the
change to use EL for the source "property".
|