Tuesday, February 16, 2010

Grails - XML Conversion

Grails provides some effortless features for converting objects into XML, but some care is necessary when using them.

By default, the XML representation of an object is shallow - this means any reference to another domain object will be represented by the id in the xml document. If the xml document should contain the full object tree, a flag in the converter needs to be set.

Adding the following line to Config.groovy will set the default for the system
grails.converters.xml.default.deep = true

or if you prefer, you can do the same thing programatically
grails.converters.XML.use('deep')

in either case, you can test it out with the following code
def converter = new grails.converters.XML(myInstance)
converter.render(new java.io.FileWriter("c:\\output.xml"))
// or
def xmlStr = myInstance as XML


One issue we had with deep converters was that it was including too much information - our User domain class contained a (cleartext) password field which was being displayed in the resulting xml.

We can customize the behavior for transforming an object into xml by using the registerObjectMarshaller method. This method is passed a class name and a closure which handles writing the XML output. The closure has implicit access to both the instance of the encountered class and the converter used to transform it.
class User {
String login
String name
String password
}

def converter = new XML(aUser)
converter.registerObjectMarshaller(User, {user, conv ->
conv.build {
login(user.login)
name(user.name)
}
})

or you could set the converter for the entire system by putting the same code in Bootstrap.groovy
grails.converters.XML.registerObjectMarshaller(User) { user, converter ->
// same implementation as above...
}

2 comments:

  1. Hi Omaha, I found your example and it seems to be one of the only ones which shows the registration of the Marshaller from within the User domain class.

    I'm trying it out but not having much luck so I'm wondering if you could post a complete example and perhaps indicate the files they are in. Where for instance is the:
    converter.registerObjectMarshaller(User, {user, conv ->

    placed. When I try and put it within the User class I get compile errors.

    Your help is appreciated.

    Thanks
    Simon

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete