Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 34 - Pages: 3   [ 1 2 3 | Next ]
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

JGoodies: Understanding Binding - Part 3

At 1:58 AM on Mar 11, 2005, R.J. Lorimer wrote:

Welcome back for the third edition in my 'JGoodies Bindings' entries, right here at www.Javalobby.org . Miss one of the first two tips? Check them out here:

JGoodies: Understanding Binding - Part 1
JGoodies: Understanding Binding - Part 2

So, what's next on the menu when it comes to discussing JGoodies Binding? The past two days I spent all my time showing how the actual binding process worked; how, by using custom 'adapters', it was possible to auto-magically tie beans and GUI components together. This tip is going to take that new-found knowledge, and take it to the next level. I'll be introducing some concepts that help developers control the binding process - namely presentation models, buffered value models, triggers, redirection, and change tracking.

Presentation Models

Presentation models are the third (and most complex) element in a chain of elements all designed to interact with bean values. The first I discussed in Tip 1 - the property adapter. The second I discussed later in tip 1, and in more detail in tip 2 - the bean adapter. The presentation model takes the concept of the bean adapter, but moves them above and beyond into a new level that is much more configurable and pluggable. While I won't be able to cover all the features available through extension of the com.jgoodies.binding.PresentationModel , I do plan to discuss the main advantages it brings to the table.

Presentation models, just like bean adapters, help you adapt a bean's properties to GUI widgets. However, in addition to that, the presentation model also allows for the changes being performed to not only be buffered - meaning they are deferred until you say they should be committed to the bean - but to also be observed to determine what changes (if any) were made. Finally, while I didn't cover it in bean adapters even though it is actually possible there as well, the bean can be swapped out for another.

Converting Code To Use Presentation Models

At the base level, presentation models plug right in where our bean adapter was - the only major difference being we call getModel as opposed to getValueModel :

// MyBean.java
import java.beans.PropertyChangeListener;
 
import com.jgoodies.binding.beans.*;
 
public class MyBean {
 // Note you don't HAVE to use this class - you can use
 // java.beans.PropertyChangeSupport if you want.
 private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport(
   this);
 
 private boolean booleanValue;
 private String stringValue;
 
 public boolean getBooleanValue() {
  return booleanValue;
 }
 
 public void setBooleanValue(boolean newValue) {
  System.out.println("Boolean value set: " +newValue);
  boolean oldValue = booleanValue;
  booleanValue = newValue;
  changeSupport.firePropertyChange("booleanValue", oldValue, newValue);
 }
 
 public void addPropertyChangeListener(PropertyChangeListener x) {
  changeSupport.addPropertyChangeListener(x);
 }
 
 public void removePropertyChangeListener(PropertyChangeListener x) {
  changeSupport.removePropertyChangeListener(x);
 }
 
 public String getStringValue() {
  return stringValue;
 }
 
 public void setStringValue(String newValue) {
  System.out.println("String value set: "+  newValue);
  String oldValue = stringValue;
  this.stringValue = newValue;
  changeSupport.firePropertyChange("stringValue", oldValue, newValue);
 }
}
 
// Binding.java
 
import java.awt.GridLayout;
 
import javax.swing.*;
 
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.value.ValueModel;
 
public class Binding {
 
 public static void main(String[] args) {
 
  MyBean bean = new MyBean();
  PresentationModel adapter = new PresentationModel(bean);
  
  ValueModel booleanModel = adapter.getModel("booleanValue");
  ValueModel stringModel = adapter.getModel("stringValue");
 
  JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value");
  JTextField field = BasicComponentFactory.createTextField(stringModel);
  JFrame frame = new JFrame();
  frame.getContentPane().setLayout(new GridLayout(2,1));
  frame.getContentPane().add(box);
  frame.getContentPane().add(field);
  frame.pack();
  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  frame.setVisible(true);
 }
}

Ok, simple enough. Now on to the advantages.

Buffering

So what the heck is a buffered value model, and why do you care? Well, let's start talking real-world examples. You have a form on a page (let's say you created it with JGoodies Forms ), and you have an OK and Cancel button on the page (probably created using the JGoodies Forms Button Builder ) that when pressed will save the user's changes down to the bean. Uh oh. Wait a minute. If we're using these value model objects, the changes the user made will ALREADY be on the bean (incidentally, if you hadn't noticed already, when you check check-buttons, toggle toggle-buttons, or lose focus in a field you just typed in, those changes will be stuffed in to the bean immediately). So what do we do? Well, the solution with the binding framework is really quite elegant. By introducing the buffered value model (remember, we have a value model for each property), we can simply hold on to the user's change until something triggers (hey, notice the foreshadowing?) to the buffered value models that they should either commit or rollback the changes that the user made.

You may have guessed that the missing element that helps us trigger our buffered value models is the item I mentioned earlier - the com.jgoodies.binding.value.Trigger . I'll get into more details about triggers in a minute, but for the time being just assume it is a special object we can call commit or flush on to commit or... yes, you guessed it, flush the changes. So, how do we set up buffering? Well, it's actually quite easy. Step 1 - we create a trigger object and give it to our presentation model. Step 2 - we create buffered value models instead of regular value models. Step 3 - we call methods on the trigger object based on user behavior ( Note: I use the Forms button bar factory - see forms button builder tip (shameless plug) for more information):

import java.awt.GridLayout;
import java.awt.event.ActionListener;
 
import javax.swing.*;
 
import org.eclipse.swt.layout.GridData;
 
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.value.Trigger;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.factories.ButtonBarFactory;
 
public class Binding {
 
 public static void main(String[] args) {
 
  MyBean bean = new MyBean();
  
  // create a new trigger for our presentation model, and store it in the presentation model.
  final Trigger trigger = new Trigger();
  PresentationModel adapter = new PresentationModel(bean, trigger);
  
  // Get buffered model objects.
  ValueModel booleanModel = adapter.getBufferedModel("booleanValue");
  ValueModel stringModel = adapter.getBufferedModel("stringValue");
  // creates a JCheckBox with the property adapter providing the underlying model.
  JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value");
  JTextField field = BasicComponentFactory.createTextField(stringModel);
  
  // Create OK/Cancel buttons that fire the trigger
  JButton okButton = new JButton("OK");
  okButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
      // Print out a message so we can see the fruits of JGoodies' Labor.
      System.out.println("OK Button Pressed");
      trigger.triggerCommit();
   }  
  });
  
  JButton cancelButton = new JButton("Cancel");
  cancelButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
     trigger.triggerFlush();  
   }
  });
  
  JFrame frame = new JFrame();
  frame.getContentPane().setLayout(new GridLayout(3,1));
  frame.getContentPane().add(box);
  frame.getContentPane().add(field);
  // add the OK/Cancel buttons to the UI
  frame.getContentPane().add(ButtonBarFactory.buildOKCancelBar(okButton, cancelButton));
  frame.pack();
  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  frame.setVisible(true);
 }
}

Given the above code, here is what printed in my console when I 1.) Checked the check box, 2.) typed 'adsf' into the text field, and finally 3.) pressed 'OK'.

Remember, we have print statements in our bean for when the values are set. So what we are seeing is the values being set post-press of the OK button. Elementary, my dear watson.

More on Triggers

Technically speaking, the presentation model (which is the glue for all of this buffering stuff) doesn't care what object notifies the value models to commit or flush, as long as it is a value model. So, what does that mean? Well, it means that it doesn't have to be an OK/Cancel button 'actionPerformed' event that causes the trigger to fire - it could be the result of a property connector, or even just another field change. The point is, the trigger class is just a thin extension of the value model API that provides convenience methods that set the 'value' of the underlying value model. It is little different from doing this:

final ValueModel trigger = new ValueHolder();
PresentationModel model = new PresentationModel(myBean, trigger);
// ...
okButton.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent evt) {
  trigger.setValue(Boolean.TRUE);
 }
});

So, what is my point? My point is - you can cause the trigger not just by manual wiring of action listeners, but also through an bean changes, gui behaviors, etc - it's up to your imagination.

Tracking Changes

Ok, back to real world examples. So you just implemented your OK/Cancel buttons above. Problem though. You want to be able to disable the OK button if the user hasn't made any actual changes. Actually, it's not a problem at all. All it requires is enabling the button based on the isChanged and isBuffering values of the PresentationModel object. Why are there two? Well, isChanged represents whether the underlying bean has actually been changed. isBuffering just implies that there are pending changes queued up. So, how can we enable/disable our OK/Cancel button based on these values? Things get kind of 'out of the box' here. While I've shown value models and property connectors when updating your bean - there is no reason we can't use them ON the PresentationModel (which, is in itself, a bean!) We can use our PropertyConnector class to update the OK button based on whether any changes are in the queue. Note, I'll use 'isBuffering' since we are using buffered models:

import java.awt.GridLayout;
import java.awt.event.ActionListener;
 
import javax.swing.*;
 
import org.eclipse.swt.layout.GridData;
 
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.beans.PropertyConnector;
import com.jgoodies.binding.value.Trigger;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.factories.ButtonBarFactory;
 
public class Binding {
 
 public static void main(String[] args) {
 
  MyBean bean = new MyBean();
  
  // create a new trigger for our presentation model, and store it in the presentation model.
  final Trigger trigger = new Trigger();
  PresentationModel adapter = new PresentationModel(bean, trigger);
  
  // Get buffered model objects.
  ValueModel booleanModel = adapter.getBufferedModel("booleanValue");
  ValueModel stringModel = adapter.getBufferedModel("stringValue");
  // creates a JCheckBox with the property adapter providing the underlying model.
  JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel, "Boolean Value");
  JTextField field = BasicComponentFactory.createTextField(stringModel);
  JButton okButton = new JButton("OK");
  okButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
      System.out.println("OK Button Pressed");
      trigger.triggerCommit();
   }  
  });
  
  // First, disable the OK button.
  okButton.setEnabled(false);
  // Note here that we wire the OK 'enabled' state to the presentation model 'buffering' state.
  PropertyConnector.connect(adapter, "buffering", okButton, "enabled");
  
  
  JButton cancelButton = new JButton("Cancel");
  cancelButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
     trigger.triggerFlush();  
   }
  });
  
  JFrame frame = new JFrame();
  frame.getContentPane().setLayout(new GridLayout(3,1));
  frame.getContentPane().add(box);
  frame.getContentPane().add(field);
  frame.getContentPane().add(ButtonBarFactory.buildOKCancelBar(okButton, cancelButton));
  frame.pack();
  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  frame.setVisible(true);
 }
}

This is one the more impressive examples of the binding framework, I think. The property connector class really presents a lot of opportunities for simple, powerful usage - it just requires a small amount of ingenuity on your part.

Redirection

Today's last subject is bean redirection. Ok - one more time, I need to ask you to go back to a real world example. You now have a GUI where the user can interact with multiple beans. We're kind of in a sticky situation though, because we bound all of these widgets to our bean, right? Wrong! They are bound to the value models, the value models are bound to our presentation model, and the presentation model is bound to our bean! So, what does that mean? It means swapping out the bean is a PIECE OF CAKE. Just call setBean on the PresentationModel, and walk away. No really, I mean it. That's it. Don't believe me? Ok, I'll go even further and implement a JList that allows the user to select from multiple beans, updates all fields and buttons on the form, and I'll do it all without writing any new listeners. First, here is a slightly modified 'MyBean.java' that has a new 'name' property (just for the sake of visual reference):

import java.beans.PropertyChangeListener;
 
import com.jgoodies.binding.beans.*;
 
public class MyBean {
 // Note you don't HAVE to use this class - you can use
 // java.beans.PropertyChangeSupport if you want.
 private ExtendedPropertyChangeSupport changeSupport = new ExtendedPropertyChangeSupport(
   this);
 
 private String name;
 private boolean booleanValue;
 private String stringValue;
 
 public boolean getBooleanValue() {
  return booleanValue;
 }
 
 public void setBooleanValue(boolean newValue) {
  System.out.println("Boolean value set: " +newValue);
  boolean oldValue = booleanValue;
  booleanValue = newValue;
  changeSupport.firePropertyChange("booleanValue", oldValue, newValue);
 }
 
 public void addPropertyChangeListener(PropertyChangeListener x) {
  changeSupport.addPropertyChangeListener(x);
 }
 
 public void removePropertyChangeListener(PropertyChangeListener x) {
  changeSupport.removePropertyChangeListener(x);
 }
 
 public String getStringValue() {
  return stringValue;
 }
 
 public void setStringValue(String newValue) {
  System.out.println("String value set: "+  newValue);
  String oldValue = stringValue;
  this.stringValue = newValue;
  changeSupport.firePropertyChange("stringValue", oldValue, newValue);
 }
 
 public String getName() {
  return name;
 }
 
 public String toString() {
  return getName();   
 }
 
 public void setName(String newName) {
  String oldName = name;
  this.name = newName;
  changeSupport.firePropertyChange("name", oldName, newName);
 }
}

... and now here is our ComboBox selector combined with our existing form:

import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.*;
 
import org.eclipse.swt.layout.GridData;
 
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.adapter.ComboBoxAdapter;
import com.jgoodies.binding.beans.BeanAdapter;
import com.jgoodies.binding.beans.PropertyAdapter;
import com.jgoodies.binding.beans.PropertyConnector;
import com.jgoodies.binding.list.SelectionInList;
import com.jgoodies.binding.value.Trigger;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.factories.ButtonBarFactory;
 
public class Binding {
 
 public static void main(String[] args) {
 
  List possibleValues = createBeans();
 
  final Trigger trigger = new Trigger();
  // set the presentation model up to the first bean.
  PresentationModel beanPresentationModel = new PresentationModel(
    possibleValues.get(0), trigger);
 
  // create a property adapter for the presentation model 'bean' property.
  ValueModel beanProperty = new PropertyAdapter(beanPresentationModel, "bean");
  // wire our new combobox up to that property adapter.
  JComboBox comboBox = new JComboBox(new ComboBoxAdapter(possibleValues,
    beanProperty));
 
  // Get buffered model objects.
  ValueModel nameModel = beanPresentationModel.getBufferedModel("name");
  ValueModel booleanModel = beanPresentationModel
    .getBufferedModel("booleanValue");
  ValueModel stringModel = beanPresentationModel
    .getBufferedModel("stringValue");
  // creates a JCheckBox with the property adapter providing the underlying
  // model.
  JLabel label = BasicComponentFactory.createLabel(nameModel);
  JCheckBox box = BasicComponentFactory.createCheckBox(booleanModel,
    "Boolean Value");
  JTextField field = BasicComponentFactory.createTextField(stringModel);
  JButton okButton = new JButton("OK");
  okButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
    System.out.println("OK Button Pressed");
    trigger.triggerCommit();
   }
  });
 
  // First, disable the OK button.
  okButton.setEnabled(false);
  // Note here that we wire the OK 'enabled' state to the presentation model
  // 'buffering' state.
  PropertyConnector.connect(beanPresentationModel, "buffering", okButton,
    "enabled");
 
  JButton cancelButton = new JButton("Cancel");
  cancelButton.addActionListener(new ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent e) {
    trigger.triggerFlush();
   }
  });
 
  JFrame frame = new JFrame();
  frame.getContentPane().setLayout(new GridLayout(5, 1));
  frame.getContentPane().add(comboBox);
  frame.getContentPane().add(label);
  frame.getContentPane().add(box);
  frame.getContentPane().add(field);
  frame.getContentPane().add(
    ButtonBarFactory.buildOKCancelBar(okButton, cancelButton));
  frame.pack();
  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  frame.setVisible(true);
 }
 
 /**
  * @return
  */
 private static List createBeans() {
  // create a couple beans.
  MyBean bean1 = new MyBean();
  bean1.setName("Bean 1");
  bean1.setBooleanValue(true);
  bean1.setStringValue("tweedle-dee");
  MyBean bean2 = new MyBean();
  bean2.setName("Bean 2");
  bean2.setBooleanValue(false);
  bean2.setStringValue("tweedle-dum");
  List possibleValues = new ArrayList();
  possibleValues.add(bean1);
  possibleValues.add(bean2);
  return possibleValues;
 }
}

That's it! Don't believe me? Try it! Essentially, every time the JComboBox is used (and the selection changes), it tells its value model to accept the newly selected value (one of the beans). It just so happens that its value model is the value model for the property 'bean' on our PresentationModel object. Our presentation model object, as you probably remember, is the glue for our entire bean form (including the buffering). Therefore, because of some genius encapsulation, everything 'just works'.

If you have read all 3 of my tips on JGoodies binding so far, consider yourself shotgun-trained in using it. While I certainly haven't shown nearly everything that is possible, nor have I laid down the perhaps best practices in each particular case, I have shown enough that I'm hoping most anyone who has read these can get a kick-start and start developing their own thoughts and ideas on how to apply this framework.

Don't worry, though. I'm not done with you yet. My next tip will be a free-for-all on everything else binding. There are still some advanced features, and quirky things that can be done that I didn't cover today. I'd like to 'pick up the pieces' as it were and try and show you a couple more things out there that are waiting to be used!

Until next time,

R.J. Lorimer
rj -at- javalobby.org
http://www.coffee-bytes.com

1 . At 5:50 AM on Mar 11, 2005, Jamie Lawrence wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

These articles have been very interesting but I'd like to make a suggestion to JavaLobby: Why have decent articles that no one can print out and read on the bus? Surely it's not too much to provide a print stylesheet to knock off the adverts, sidebar etc?
2 . At 9:48 AM on Mar 11, 2005, Matthew Schmidt wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Hi Jamie. We'll take a look at this, it shouldn't be too hard. Thanks for reminding me of this :)

-Matt
www.dzone.com - fresh links for developers
bestuff.com - the best stuff in the world
3 . At 10:04 AM on Mar 11, 2005, Pepijn Van Eeckhoudt wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Thank you for the great articles R.J.
I had looked at the binding framework before and found it interesting but hard to comprehend based on the presentations alone. Your series of articles has made the learning curve much easier. Looking forward to the next one...
4 . At 10:36 AM on Mar 11, 2005, Pepijn Van Eeckhoudt wrote:
  Click to reply to this thread Reply

Relationship with JDNC binding?

Is there any coordination between the work that is being done in the JDNC data binding framework or are these just two completely seperate projects?
5 . At 12:42 PM on Mar 11, 2005, Richard Osbaldeston wrote:
  Click to reply to this thread Reply

Awkward questions

Very interesting, thanks R.J! Was a little disturbed by the lack of multiple selections in lists though couldn't help wondering if it wasn't indicative of further problems with the more complex widgets.. tables & trees. Just wondering if I tried to integrate binding whether I'd come unstuck at a certain point. As I'm usually fronting a db I use LOTS of tables, and in particular was wondering how binding might help (or hinder) when it comes to not only the binding of beans to rows & columns but the added cell-renderers and cell-editors issues. I'm often in a position where the rendering and/or editing of a cell is dependant on some other property of the row object and invariably end up with domain objects in the renderer etc.. the kind of tight coupling we're trying to avoid.

Also wondered about the buffer behaviour if exceptions occur during a commit cycle. I use something similar in my own code although I buffer a set of commands objects for a dialog editing session. When It comes to commit (execute) time on OK/Apply I'll sometimes get exceptions from db somewhere down the chain - triggers and the like. With binding do I lose all the buffered changes (rollback)? or just the changes up to the point of the first problem? i.e. can I tell what's been lost?

- Richard
6 . At 12:48 PM on Mar 11, 2005, Richard Osbaldeston wrote:
  Click to reply to this thread Reply

Re: Relationship with JDNC binding?

They're separate implementations and not the only ones I believe Spring RCP has its own binding framework and I've toyed with the idea of an OGNL binding for Swing framework.

In all fairness to JDNC I believe they were expressing interest in making it flexible enough to delegate binding to JGoodies or use their own.. I'm not sure how far they got with that idea - but then binding 1.0 has only just been released..

- Richard
7 . At 2:03 PM on Mar 12, 2005, Shoaib Akhtar wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Hi,
First of all, congratulations for such a nice series of articles. I have some questions regarding the use of binding in three tier architecture. In such an anarchitecture Swing is at front end EJBs (or Spring) for business layer and JDBC or hibernate at backend. The domain model objects usually comes from Database and there values are set in middle tier and send back to the front end swing app and in that case the PropertyChangeSupport or Obsever pattern does not work as setters are called on the tier (middle tier) that resides on different layer.
So how binding handle this problem should we call setter of every property ourself or there is some nice solution? Please help me. Thanks
8 . At 3:07 PM on Mar 12, 2005, Mark N DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Excellent articles. I just started another Swing UI project and had wanted to use the binding framework. I wasn't (short on time) until I saw these articles. I can't wait to get it all working next week. It will save me a bunch of time. With things like this, I can't see how anyone would consider Web apps (unless there is NO choice).
9 . At 4:10 AM on Mar 13, 2005, SyntEvo GmbH wrote:
  Click to reply to this thread Reply

Possible to avoid reflection?

First, R.J., I very much appreciate your tutorials. Do you make them in your spare time (aka for free)?

OK, now to JGoodies Bindings. Could you please provide a detailled example which avoids reflection (and hence JavaBeans) completely? Is it possible at all?

We avoid reflection whereever possible like the devil the holy water. Why we restrict us to non-relection code?
- because you cannot detect for sure any more, whether a method is used in your project,
- because you cannot rename methods without the risk to break code,
- because broken code only can be found at runtime, not at compile time (and seriously, who has a unit test for *every* [public] method call?),
- because reflection makes obfuscation a nightmare.

--
Thanks in advance.
Thomas Singer


PS: BTW, our persistence framework used in Smart[CVS|SVN] and other applications does not use reflection and still is very easy to use.
SmartCVS | SmartSVN | SmartSynchronize - smart tools for smart developers
10 . At 7:21 AM on Mar 13, 2005, Ragnar Westad wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Thanks for some very enlightening articles.

Seems like there is a lot of nice features in this framework.

Admittedly I have just skimmed the articles and the framework, but since I have a few questions around issues also touched by others but not yet fully answered, I present them here:


1) Requiering domain beans to extend a JGoodies class (referring to the Album bean in the tutorial) will not work in real life situations where the beans live on a serverside. I can easily imagine the jaw-dropping effect on the server side team as I tell them that: "Hey, and all value objects that I receive must extend the JGoodies Model class!" :-)

2) Requireing domain beans to publish property change events have similar problems as above, but at least it is a pure Java beans standard and does not tie the server code to a client framework. But still, it will not be easy to have this integrated in server side code, since it probably will be dead code to everyone on that side of the fence. And if I am to implement a GUI for a server side solution that is already implemented, it will not work. The chances that they emit property changes are close to zero.

3) Most server side beans that I have worked with have get'ers and set'ers for their properties and nothing more. I cannot see that the JGoodies binding works for these. The Model class constructor throws a "PropertyUnboundException if the bean does not provide a pair of methods to register a PropertyChangeListener".

And after all, 3) is the most common case, right? I hope I am wrong when I say it is not supported by the JGoodies binding framework because it sure have to in order to be usable to me!

If not directly supported, it would be nice to have some guidance on how to adapt such simple beans to the binding framework.

That said, I really like the approach taken and I think property change listeners on beans are a good idea. It's just not that common to be relied upon beeing present.


Regards,

/Ragnar
11 . At 2:58 PM on Mar 13, 2005, Mark N DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Ragnar,
You should be able to solve some of this (2 and 3) with AOP. If you have access to the code, if should be pretty easy. I don't think you have to subclass anything. R.J.'s tips don't include any so #1 isn't a problem either.
12 . At 3:07 PM on Mar 13, 2005, Mark N DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Possible to avoid reflection?

It probably could be done with annotations. But then you have extra "code" in your class. If Java had method pointers you could do it with out reflection that way.

The issue you have is not so much reflection, as it is using strings do do reflection. But I see your point. It is a downside of Reflection. For the very same reason I despise web apps (and more so).

I don't think the use of reflection has anything to do with ease of use. And I am sure your products are easy to use. But you wouldn't be looking at JGoodies Binding if you didn't have some need for what it provides.
13 . At 6:41 PM on Mar 13, 2005, R.J. Lorimer wrote:
  Click to reply to this thread Reply

Re: JGoodies: Understanding Binding - Part 3

Ragnar,

Mark is right in his response regarding #1 - you do not have to extend any JGoodies class. As he pointed out, none of my 'beans' do so.

Regarding 2&3.

First, if you have some sort of notification mechanism other than property change events or observables, you can use it by implementing custom adapters. I plan to discuss one such example (the PreferencesAdapter) in my final tip.

Second, you can use AOP as I believe Mark suggested to make it so the beans on your side can fire the property change events. It's relatively simple to wrap a bean with AOP and add functionality - though I don't have time to show an example along with training in the AOP tool here :).

If AOP is too much, you can always wrap the bean with a view-enabled bean - this will quickly begin requiring a significantly larger amount of code, but it is an AOP-free way to decorate a bean for your view:

Bean myBean = getServerSideBean();
ViewBean viewBean = new ViewBean(myBean);
 
// ViewBean.java
public class ViewBean {
 private Bean trueBean;
 
 public ViewBean(Bean bean) {
  trueBean = bean;
 }
 
 public String getValue1() {
  return trueBean.getValue1();
 }
 
 public void setValue1(String newValue) {
  String oldValue = trueBean.getValue1();
  trueBean.setValue1(newValue);
  // fire property change event for old and new values.
 }
}
Best, R.J. Lorimer
14 . At 7:07 PM on Mar 13, 2005, R.J. Lorimer wrote:
  Click to reply to this thread Reply

Re: Possible to avoid reflection?

Thomas,

Thanks for your kind words. The tips/tricks/tutorials I post here are part of my effort as a member of the Javalobby team. By day I am a full time consultant in the enterprise Java industry.

Regarding your need to avoid reflection. While it may require more code on your part, it is certainly possible.

As currently designed, there are just a few too many finals to make your custom value model implementation easy to integrate into the higher level APIs such as presentation model and bean adapter. If you find the need, I'm sure an RFE could be introduced at the binding dev page:
https://binding.dev.java.net.

That being said, it is possible to implement custom value models (which are the objects that are plugged in to the various view model adapters). For instance (please note, I have not implemented a complete value model here - you must also do things such as forward the property change events through. I am just showing the meat of it here):

// MyBean.java
public class MyBean {
 private String string1;
 private String string2;
 
 public String getString1() { return string1; }
 public String getString2() { return string2; }
 public void setString1(String stringVal) { string1 = stringVal; }
 public void setString2(String stringVal) { string2 = stringVal; }
}
 
// MyBeanAdapter.java
public class MyBeanAdapter implements ValueModel {
 public enum Field { STRING1, STRING2 };
 
 private Field adaptedField;
 private MyBean bean;
 
 public MyBeanAdapter(MyBean newBean, Field field) {
  adaptedField = field;
  bean = newBean;
 }
 
 public void setValue(Object o) {
  switch(adaptedField) {
   case STRING1:
    bean.setString1((String)o);
    break;
   case STRING2:
    bean.setString2((String)o);
    break;
  }
 }
 
 public Object getValue() {
  switch(adaptedField) {
   case STRING1:
    return bean.getString1();
   case STRING2:
    return bean.getString2();
  }
 }
 
 // Event forwarding methods here... see PropertyAdapter source for example...
}
 
// usage
MyBean bean = getBean();
ValueModel string1Model = new MyBeanAdapter(bean, MyBeanAdapter.Field.STRING1);
ValueModel string2Model = new MyBeanAdapter(bean, MyBeanAdapter.Field.STRING2);
 
JTextField string1Field = BasicComponentFactory.getTextField(string1Model);
JTextField string2Field = BasicComponentFactory.getTextField(string2Model);


With some smart super-classing, and maybe a little help from JGoodies in Binding 1.0.1 :) you should be able to do exactly what you need.

Good luck,

R.J.
Best, R.J. Lorimer

thread.rss_message