Mittwoch, 8. Februar 2012

Groovy Beans To Json

Groovy bietet mit dem groovy.json.JsonBuilder und dem groovy.json.JsonBuilder sehr gute und einfache Möglichkeiten zur Json-Verarbeitung. Hier sollen einfache Groovy Beans (POGO's - Plain Old Groovy Objects) in Json Objekte und wieder zurück transformiert werden.

Dies ist ja dank Builder und Slurper kein Hexenwerk mehr. Das Beispiel-Bean ist folgendes (beliebig austauschbar):

class Book {
    String title
    String author
}



Bean To Json

String toJsonImpl(def bean) {

    JsonBuilder builder = new JsonBuilder()
    builder {
        // Hier folgen Schlüssel und Wert des Eintrags
        // dabei ist eine Variable als Schlüssel nicht möglich
        // deshalb "${ ... }"
        "${ bean.class.getName() }" bean
    }

    return builder.toString()
}

Nun ist folgender Aufruf möglich:

assert '{"Book":{"title":"Die Entw...","author":"G.S."}}'
    == JsonUtil.toJsonImpl(new Book(title: "Die Entw...", author: "G.S."))

Um die Klassen eindeutig identifizieren zu können, wird hier als Json-Key auf oberster Ebene der Name der Klasse benutzt. Und nun der Weg zurück...



Json To Bean

def toBeanImpl(String json) {

    JsonSlurper slurper = new JsonSlurper()
    def beanData = slurper.parseText(json)

    String beanClassName
    Map beanParameter
    beanData.eachWithIndex { key, value, index ->
        if (index == 0) {
            beanClassName = key
            beanParameter = value
        }
    }

    def beanInstance = Class.forName(beanClassName)
            .newInstance(beanParameter)
    return beanInstance
}

Damit ist der Aufruf möglich:

assert JsonUtil.toBeanImpl(
        '{"Book":{"title":"Die Entw...","author":"G.S."}}').properties
        == new Book(title: "Die Entw...", author: "G.S.").properties



Meta Programming

Jetzt können die beiden Funktionen noch an die Beispielklasse “angehängt“ werden. Dass kann zum Beispiel beim automatischen Anhängen an eine Reihe von Klassen interessant sein:

Book.metaClass.toJson = {
    return JsonUtil.toJsonImpl(delegate)
}

Book.metaClass.'static'.toBean = { String json ->
    return JsonUtil.toBeanImpl(json)
}

Die Methode “toBean“ wurde dabei statisch (an der Klasse) hinzugefügt.
Jetzt ist der Aufruf toJson() direkt an der Instanz und toBean(...) an der Klasse möglich:

Book bookBean = new Book(title: "Groovy in Action", author: "Dierk Konig")
String jsonBook = bookBean.toJson()
Book bookBean2 = Book.toBean(jsonBook)
assert bookBean.properties == bookBean2.properties


Na dann viel Spaß beim “Bauen“ und “Schlürfen“.