Search code examples
jsongrailsconstructorgrails-ormtransient

Grails: setting transient fields in the map constructor


I'm trying to persist Maps of properties as single JSON-encoded columns, as shown in this question.

The problem I'm having is that apparently transient properties cannot be set in the default map constructor. Given any transient field:

class Test {
    //...
    String foo
    static transients = ['foo']
}

It seems that the map constructor (which Grails overrides in various ways) simply discards transient fields:

groovy:000> t = new Test(foo:'bar')
===> Test : (unsaved)
groovy:000> t.foo
===> null

While direct assignment (through the setter method) works as expected:

groovy:000> c.foo = 'bar'
===> bar
groovy:000> c.foo
===> bar

Is there a way to make the map constructor accept transient fields?


Or rather: is there a better way to persist a Map as a single JSON-encoded DB field, rather than the method shown in the linked question?

Here's the complete example:

import grails.converters.JSON

class JsonMap {
    Map data
    String dataAsJSON

    static transients = ['data']
    def afterLoad()      { data = JSON.parse(dataAsJSON) }
    def beforeValidate() { dataAsJSON = data as JSON }
}

I can set data using the setter (which will then be converted into dataAsJSON) but not using the map constructor.


Solution

  • The map constructor in GORM uses the data binding mechanism, and transient properties are not data-bindable by default. But you can override this using the bindable constraint

    class Test {
        //...
        String foo
        static transients = ['foo']
    
        static constraints = {
            foo bindable:true
        }
    }