The Source for Java Technology Collaboration
User: Password:



Shannon Hickey's Blog

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".





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds