This isn’t much of anything, really. More the beginings of ideas, but I was chatting with Josh Marinacci earlier about databinding in Swing, and frankly, how completely unimpressed I am by what I have seen of JSR-295. Honestly, I implemented all of the functionality I have seen there in about a week on my own. Having a whole spec that does, frankly, that little work for me doesn’t get me all hot and bothered.

I made some notes about what I consider — off the top of my head — the ultimate Swing binding framework. I don’t pretend that all the issues have been worked out, but I think it is a good starting place to think about it.

More after the bump.

Please forgive my ignorance here. I am not the Swing master by any stretch — indeed large parts of the API are completely unknown to me — but this comes from my limited experience doing basic Swing stuff as a JEE guy. I know component or container would likely be better than what I am talking about below, but I think in terms of JPanel, so that is what I am going to talk about…

First, a Bean - JPanel class binding factory. This would have 3 basic operating modes: first, convention: If you have

com.something.model.Vehicle

and

com.something.view.Vehicle,

I should be able to register with the factory a package mapping:

BindingFactory.mapPackages( com.something.model , com.something.view );

Alternately I should be able to use an annotation:

@BindingSource( class=com.something.view.Vehicle )
public class VehicleView extends JPanel{

}

Both of these would allow me to do something like:

JPanel someVehicleView = BindingFactory.getView( someVehicleInstance );

Thirdly, I should be able to specify at construct time what I want:

JPanel someVehicleView = BindingFactory.getView( someVehicleInstance );

By default properties on the view instance should map to similarly named properties on the constructed panel:

model.Vehicle {
int .year
String .make
String .model
}

view.Vehicle {
JTextBox .year
JTextBox .make
JTextBox .model
}

These should be resolved to the usual “value” property on the associate widget for standard Swing types — .value for sliders .text for textBoxes, into DocumentModel for textareas…. You should also be able to specify a formatter as an annotation:

@Formatter( class=com.something.view.formatters.YearFormatter )
public JTextBox getYear();

Additionally you should have a way to specify the binding, to avoid Swing collisions or for whatever reason

view.Vehicle{
@Bind( property=”color” )
JTextBox .vehicleColor
}

If you have a custom widget, you should be able to annotate it to specify what the “value” field is:

@DefaultValue
public Object getMyCustomDefaultValue

Mappings for most types would generally be obvious — moving String to int, Integer, Float, etc. I would add a couple of annotations to help clear up the common cases:

@DefaultValue
@EmptyIsNull
public String getValue()

sets non-primitive properties to null if the value is an empty String. You could also use @Trim to default call .trim() on the property before conversion. Stacked, with @EmptyIsNull means ” ” would be null as well.

If the property on the view class is a JPanel, when contructing/binding, it should have its only contained widget set to the result of BindingFactory.getView( theProperty ). That is, if you have:

model.Vehicle {
model.Stereo .stereo
}

and

view.Vehicle {
JPanel .stereo
}

Then the JPanel should get populate with (by default) view.Stereo, and the view.Stereo should be removed on change.

If the model property is a collection, and the view property is a JPanel, then it should be resolved and each of the items in the collection should be passed to the BindingFactory and the resultant widget added to the panel:

model.Vehicle {
List .dealerOptions
}

view.Vehicle {
JPanel (Container?) .dealerOptions
}
Both of these should have annotations on the view layer like @HideOnNull to setDisplay(false) if the property is null or @HideOnEmpty if the collection is empty. They should also support overriding the default class for display. For instance, I might have view.Stereo, but on the Vehicle panel, I just want summary information, I would want to override the default binding with a specific class:

view.StereoSummary extendsJPanel {} ….

view.Vehicle{
@ViewClass(class= view.StereoSummary)
JPanel .stereo
}

When dealing with collections, you still have the problem of change notifications from the collections. I guess you could do this through wrapper classes, but you run into problems with custom collection types. /shrug. Ideally you would want .add and .remove to work on the JPanel objects as they work on the containers, matching the widgets based on the instance equality of whatever the @DefaultValue for the contained panels are. The big thing here is to not have to modify the model to suit the view, as models tend to be shared, autogenerated, etc.

I guess I could go on and on about other cases: ComboBoxes come to mind as something that seems particularly an issue: you can bind a combo box to a property, but you need a way to assign the list of options to it, perhaps with some kind of factory interface specified as an annotation. I would add to that an option to give a property name or a formatter to control what shows up in the combo box — writing a ton of wrappers to give the correct .toString() is annoying. I have a couple of applications where I have the same bean type but I want different properties to appear as the option text in a combo box in different contexts.