Geertjan's Blog

  • June 26, 2012

BeansBinding Across Modules in a NetBeans Platform Application

Geertjan Wielenga
Product Manager

Here's two TopComponents, each in a different NetBeans module. Let's use BeansBinding to synchronize the JTextField in TC2TopComponent with the data published by TC1TopComponent and received in TC2TopComponent by listening to the Lookup.

The key to getting to the solution is to have the following in TC2TopComponent, which implements LookupListener:

private BindingGroup bindingGroup = null;
private AutoBinding binding = null;
public void resultChanged(LookupEvent le) {
if (bindingGroup != null && binding != null) {
if (!result.allInstances().isEmpty()){
Customer c = result.allInstances().iterator().next();
// put the customer into the lookup of this topcomponent,
// so that it will remain in the lookup when focus changes
// to this topcomponent:
ic.set(Collections.singleton(c), null);
bindingGroup = new BindingGroup();
binding = Bindings.createAutoBinding(
// a two-way binding, i.e., a change in
// one will cause a change in the other:
// source:
c, BeanProperty.create("name"),
// target:
jTextField1, BeanProperty.create("text"),
// binding name:

I must say that this solution is preferable over what I've been doing prior to getting to this solution: I would get the customer from the resultChanged, set a class-level field to that customer, add a document listener (or action listener, which is invoked when Enter is pressed) on the text field and, when a change is detected, set the new value on the customer. All that is not needed with the above bit of code.

Then, in the node, make sure to use canRename, setName, and getDisplayName, so that when the user presses F2 on a node, the display name can be changed. In other words, when the user types something different in the node display name after pressing F2, the underlying customer name is changed, which happens, in the first place, because the customer name is bound to the text field's value, so that the text field's value will also change once enter is pressed on the changed node display name.

Also set a PropertyChangeListener on the node (which implies you need to add property change support to the customer object), so that when the customer object changes (which happens, in the second place, via a change in the value of the text field, as defined in the binding defined above), the node display name is updated.

In other words, there's still a bit of plumbing you need to include. But less than before and the nasty class-level field for storing the customer in the TC2TopComponent is no longer needed. And a listener on the text field, with a property change listener implented on the TC2TopComponent, isn't needed either. On the other hand, it's more code than I was using before and I've had to include the BeansBinding JAR, which adds a bit of overhead to my application, without much additional functionality over what I was doing originally. I'd lean towards not doing things this way. Seems quite expensive for essentially replacing a listener on a text field and a property change listener implemented on the TC2TopComponent for being notified of changes to the customer so that the text field can be updated. On the other other hand, it's kind of nice that all this listening-related code is centralized in one place now.

So, here's a nice improvement over the above. Instead of listening for a customer, listen for a node, from which the customer can be obtained. Then, bind the node display name to the text field's value, so that when the user types in the text field, the node display name is updated. That saves you from having to listen in the node for changes to the customer's name. In addition to that binding, keep the previous binding, because the previous binding connects the customer name to the text field, so that when the customer display name is changed via F2 on the node, the text field will be updated.

private BindingGroup bindingGroup = null;
private AutoBinding nodeUpdateBinding;
private AutoBinding textFieldUpdateBinding;
public void resultChanged(LookupEvent le) {
if (bindingGroup != null && textFieldUpdateBinding != null) {
if (bindingGroup != null && nodeUpdateBinding != null) {
if (!result.allInstances().isEmpty()) {
Node n = result.allInstances().iterator().next();
Customer c = n.getLookup().lookup(Customer.class);
ic.set(Collections.singleton(n), null);
bindingGroup = new BindingGroup();
nodeUpdateBinding = Bindings.createAutoBinding(
n, BeanProperty.create("name"),
jTextField1, BeanProperty.create("text"),
textFieldUpdateBinding = Bindings.createAutoBinding(
c, BeanProperty.create("name"),
jTextField1, BeanProperty.create("text"),

Now my node has no property change listener, while the customer has no property change support. As in the first bit of code, the text field doesn't have a listener either. All that listening is taken care of by the BeansBinding code. 

Thanks to Toni for help with this, though he can't be blamed for anything that is wrong with it, only thanked for anything that is right with it. 

Join the discussion

Comments ( 3 )
  • Philip Markus Tuesday, June 26, 2012

    I'm not sure, but isn't a property change support needed for the auto binding to work from the bean side? At least this is what i have experienced.

  • Geertjan Tuesday, June 26, 2012

    Yeah, me too, on second thoughts. Without the property change support on the bean, the node display name is only updated when you select a different node and then come back to the node that you changed. But if you include property change support on the bean, the update is done immediately.

  • Fabrizio Giudici Thursday, June 28, 2012

    Yes, you need bound property support, but I'd say it's a small price to pay for a decoupled architecture. You can have NetBeans to auto-generate the plumbing code for bound properties, or even use an annotation processor such as Lombok / Lomprop.

    I've been using binding, an in particular BeansBinding and BetterBeansBinding, for years with a great satisfaction. The only reason for which I'm going to change it is that the future is probably in the new binding facility that comes with JavaFX 2. I'm just waiting for an official release for Linux to start using it (and have customers to start using it).

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.