I *was* supposed to look into integrating Commons Validators into the JavaBuilder concept, but occasionally one had that flash of inspiration where for a moment you cross into "mad scientist" territory...and this week had one of those. I've added a new concept to YAML that I call "virtual constructor flow" that basically compacts the file format to the maximum level allowed by natural law. :-)
OK, but let's start from the beginning. Let's say we have a typical builder file like this in YAML, with the traditional YAML white-space indentaton to indicate hierarchy:
JFrame:
name: myFrame
title: My App Frame
state: max
YAML supports the concept of alternate flows, hence the same data can be expressed in-line, which basically turns a portion of it into JSON:
JFrame: {name: myFrame, title: My App Frame, state: max}
This is very cool and it helps to reduce the number of lines in a file. However, it does not work if the node in question has additional child nodes. In Java SwingBuilder, by convention children are grouped under the "content" list node (same name as in JavaFX...not a coincidence, obviously):
JFrame:
name: myFrame
title: My App Frame
state: max
content:
- JPanel:
name: mainPanel
content:
- JButton: {name: okButton, text: OK}
The limitation / design (?) of YAML is that once you escape into the JSON format the entire child node has to be expressed in it, even if it has children of its own. This unfortunately would lead to many nested "{", "}", "[", "]" brackets (if you've seen any serious JavaFX code, you will see it often has lots of secton with 10 or more levels of nested brackets of various type).
So, if I wanted to cut down on the number of lines in a file and do it all inline it loses all the nice, clear YAML whitespace indentation and descends into JSON closing bracket hell:
JFrame: {name: myFrame, title: My App Frame, state: max, content: [
{JPanel: {name: mainPanel, content: [
{JButton: {name: okButton, text: OK}}
]}
]}
In other complex file very soon you will have multiple levels of nested "}]}" type closing brackets, which makes it very unreadable IMHO. That's why I opted for YAML instead of JSON.
What I would like to do is to use the in-line formats for the properties belonging to the current node and then go back to regular white-space YAML for its children, e.g.:
JFrame: {name: myFrame, title: My App Frame, state: max}
content:
- JPanel: {name: mainPanel}
content:
- JButton: {name: okButton, text: OK}
However, this is not allowed in YAML and the YAML parsing library will exit with an exception. It's all whitespace or it's all JSON-style brackets, but you can't mix and match them.
So, this is where the mad scientist mode entered. I decided to add a new flow type to YAML via a custom preprocesor that I call "virtual constructor flow" and it looks like this:
JFrame(name=myFrame, title=MyAppFrame, state=max):
content:
- JPanel(name=mainPanel):
content:
- JButton(nam=okButton, text=OK)
This is still valid YAML (it gets processed without errors), but obviously the child properties are now embedded directly into the YAML node definition, so it does not know about them, it just sees a node defined as
JFrame(name=myFrame, title=MyAppFrame, state=max)
The JB pre-processor will take the YAML Object and do a second pass through and "explode" those properties embedded int the virtual constructor flow and create at run-time the exact same "pure" YAML hierarchy as seen at the beginning.
Also, the pre-processor does some nifty stuff such as if a node is defined right off the bat as a list (e.g. "JFrame: " with "- JButton", "- JLabel" nods underneath it) it will property "move" the list one level down to the default "content" node.
Therefore all we have left is:
JFrame(name=myFrame, title=MyAppFrame, state=max):
- JPanel(name=mainPanel):
- JButton(nam=okButton, text=OK)
A lot less than the original input:
JFrame:
name: myFrame
title: My App Frame
state: max
content:
- JPanel:
name: mainPanel
content:
- JButton: {name: okButton, text: OK}
but at run-time the pre-processor will "explode" the compressed format to
exactly the same thing.
Now you are wondering, "well OK, this is cool, but is it really worth it to bastardize YAML with some sort of custom extension?". And the answer is YES, it is worth, 'cause it brings amazing reduction in the size and levels of indentation when defining UIs via Java SwingBuilder.
Let's say we have a simple JFrame with 3 main menus and some child menus underneath them:

The pure YAML version of the build file for this looks like this:
http://code.google.com/p/javabuilders/source/browse/trunk/org.javabuilders.swing/samples/org/javabuilders/swing/samples/menu/FrameWithMenu.yamlbut the compressed version is WAY smaller less verbose:
http://code.google.com/p/javabuilders/source/browse/trunk/org.javabuilders.swing/samples/org/javabuilders/swing/samples/menu/FrameWithMenuCondensed.yamlBasically, this allows you across the board to define an entire object and all of its properties in one line of "enhanced" YAML using the virtual constructor flow.
The latest build of Java SwingBuilder with support for this enhanced format is up on
javabuilders.org.
P.S. Here's another form converted to the new format with before/after samples:
Before:
http://code.google.com/p/javabuilders/source/browse/trunk/org.javabuilders.swing/samples/org/javabuilders/swing/samples/binding/BindingFrame1.yaml?r=150After:
http://code.google.com/p/javabuilders/source/browse/trunk/org.javabuilders.swing/samples/org/javabuilders/swing/samples/binding/BindingFrame1.yaml?r=157Less code and less lines to type = good! :-)