Griffon YAML-JSON converter

Griffon quick app

Griffon is a Groovy desktop application framework. It’s very neat, allowing to build a lot without having to write tons of boilerplate code. I’m going to make a simple griffon application here to convert between YAML and JSON. I needed this yesterday for a separate project, so I figured out I’d share the whole process here. So, let’s get going.

To create a griffon application, you do the following:

griffon create-app YamlJsonConverter
cd YamlJsonConverter

This will create YamlJsonConverter folder in the current working folder. You can read more about this and other commands (and Griffon in general) in the Griffon guide – click on create-app on the left, under Command Line.

This will also create YamlJsonConverterModel, YamlJsonConverterControllef and YamlJsonConverterView that will suffice for this project. Let’s go one by one – just after we set it up in our favorite IDE. I’ll use Eclipse for this one.

Setting up Eclipse

I will not go into setting up Groovy support for Eclipse – take a look here for more info, it’s straightforward, as there’s an Eclipse Groovy plugin.

For Griffon, you don’t need too much – you just need to add a couple of variables. One is GRIFFON_HOME, which you should point to the folder where you unzipped Griffon. The second is IVY2_CACHE, which should point to your local Ivy cache. Eclipse uses its own project files, which Griffon fortunately can generate them with the help of the EclipseSupport Plugin. Run the following:

griffon install-plugin eclipse-support
griffon eclipse-update

The second command is not necessary the first time you install plugin, as it will be run automatically, but will be helpful when you add dependencies to BuildConfig.groovy file later – just run it and refresh in Eclipse to get your new dependencies.

After the above, creating the project with the same name will make it available – so right click in package view, New > Groovy Project, name it YamlJsonConverter and click Finish – that should be all. You should see our MVC under griffon-app + /model, /controller and /view, respectively.

Model

Open YamlJsonConverterModel.groovy and make it like following:

package yamljsonconverter

import groovy.beans.Bindable

class YamlJsonConverterModel {
   @Bindable yaml = 'Put YAML here'
   @Bindable json = 'Put JSON here'
   @Bindable messages = 'Welcome to YamlJsonConverter!'
}

The above will add three properties to the model – yaml, json and messages. @Bindable will make it bindable – we will use this in our view, but basically it will make it fire property change events that you can bind to and monitor the changes appropriately.

View

Griffon has a concept of UberBuilder – this is a builder composed of many other builders and used as a base for GUIBuilder, used to build views. One of the builders is SwingBuilder – this can be configured in griffon-app/conf if needed. We will use SwingBuilder to build our little GUI. The GUI is simple – it will have two text boxes for Yaml and Json text, two buttons to convert Yaml -> Json and Json -> Yaml and a message box for displaying useful and error information.

I like MiGLayout for which Griffon also has a plugin, so we’ll install and use that:

griffon install-plugin miglayout

We’ll also make it a bit fancy and add some images. Griffon has some image-container plugins, we’ll use one of them:

griffon install-plugin crystalicons

Then we will make our view like this:

package yamljsonconverter

import javax.swing.event.DocumentListener

actions {
  action(id: 'toYaml', name: 'To YAML', 
    smallIcon: crystalIcon(icon: '1downarrow1', size: 32), closure: controller.&toYaml)  
  action(id: 'toJson', name: 'To JSON', 
    smallIcon: crystalIcon(icon: '1downarrow', size: 32), closure: controller.&toJson)  
}

application(title: 'YamlJsonConverter',
  pack: true,
  locationByPlatform:true,
  ) {
  migLayout(layoutConstraints: 'fill, gap 0',
    rowConstraints: '[fill][][fill]', 
    columnConstraints: '[fill,200][fill,200][fill,400]')
  
  textArea(id: 'yaml', text: bind { model.yaml }, constraints: 'spanx 2, height 300')
  yaml.document.addDocumentListener({
    doLater { model.yaml = yaml.text }
  } as DocumentListener)
  textArea(id: 'messages', text: bind { model.messages }, constraints: 'spany 3, width 300, wrap')
  button(id: 'toYaml', action: toYaml, constraints: '')
  button(id: 'toJson', action: toJson, constraints: 'wrap')
  textArea(id: 'json', text: bind { model.json }, constraints: 'spanx 2, height 300')
  json.document.addDocumentListener({
    doLater { model.json = json.text }
  } as DocumentListener)
}

As you can see in handful of lines we made the whole view. application tag basically says that you start the main frame of the view. Griffon uses application instead of frame as it can be run as an applet, standalone application or through Web Start. Other things are basically from SwingBuilder – actions in front for our two actions, migLayout from MiGLayout plugin to define the constraints and the five controls we need. You may want to read the MiGLayout cheat sheet to understand MiGLayout a bit better – it can be confusing from time to time, but it pays off.

We also made a two-way binding between yaml and json in view and model, that was not strictly necessary, but it shows that implementation is trivial.

The only thing left is to make the actual controller logic.

Controller

The controller only needs to implement the two methods called from the view – toYaml and toJson. For YAML, I’ll use snakeyaml, so let’s add that to our dependencies – they live in grifoon-app/conf/BuildConfig.groovy. For JSON, I’ll use json-lib. Find the dependencies section and add the following:

compile 'org.yaml:snakeyaml:1.8'
compile group:'net.sf.json-lib', name:'json-lib', version:'2.4', classifier:'jdk15'
compile 'commons-lang:commons-lang:2.6'
compile 'net.sf.ezmorph:ezmorph:1.0.6'
compile 'commons-collections:commons-collections:3.2.1'

There are a few more dependencies that are required by json-lib, but now we have all we need – this is the whole controller:

package yamljsonconverter

import org.yaml.snakeyaml.Yaml;
import net.sf.json.JSONObject
   
class YamlJsonConverterController {
    def model
    def view

    def toYaml = {
      def data = JSONObject.fromObject(model.json)
      appendMessage(['toYaml', data])
      model.yaml = new Yaml().dump(data)
    }
    
    def toJson = {
      def data = new Yaml().load(model.yaml)
      appendMessage(['toJson', data])
      model.json = JSONObject.fromObject(data)
    }
    
    def appendMessage = { message ->
      model.messages += "\n$message"
    }
}

Try running it now:

griffon run-app

You will get something like this:

Try both buttons and play around with it.

Limitations

One thing I spotted is that json-lib is “type-safe” – you cannot use JSONObject.fromObject() to work with arrays (there’s JSONArray for that). With the given code, only direct object serialization is possible, but that was not a problem for me.

Conclusion

I find the above a very good demonstration of all the pieces included – Griffon, MiGLayout, SnakeYaml and json-lib. SwingBuilder and its binding were a great help. Crystal Icons were a nice touch. Worked fine for what I needed – I could not have asked for more, now, could I?

You can checkout the code from github – the main page is here:

git clone git://github.com/icyrockcom/YamlJsonConverter.git