Using bindData Method in a Grails Service

Posted by jt - 05/01/10 at 06:01 pm

Grails controllers get a method called bindData which allows you to take the parameters map and bind the values to the properties of a domain object.  The method works nicely because it handles a lot of the type conversions for you.  This method works similar in fashion to the properties method, but it offers you more control.  Using bindData, you can include or exclude properties.   Here is the complete documentation for the bindData method.

I have a service which parses xml to domain objects.  I originally was walking the xml, casting the name value pairs to a map, and then using the properties method.  This was working well for me, until I needed the control offered by the bindData method.  When I tired to switch, I ran into a small gotcha.  Grails was throwing a method not found error.  Turns out bindData is a dynamic method that the Grails framework adds to controllers for you, but not services.

After a little digging through the Grails source code, I found the class used for the bindData dynamic method.  To add it to your services you will need to import the following:

import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod

I’m not going to get too fancy for a one off usage.  I just need to create an instance and call the invoke method. The method signature of invoke is Object, string, Object[]. I originally wrote my call as follows:

        BindDynamicMethod bind = new BindDynamicMethod()
 
        def args =  [ po, params, [exclude:['supplierAddress', 'shipToAddress', 'billToAddress', 'purchaseOrderDetail' ]] ]
 
        bind.invoke( po, 'bind', args)

But this was not happy in crossing the Goovy/Java barrier.  Groovy was treating my ‘args’ object as an ArrayList, not an array of Objects.  ANd Java was not happy about this.  Easy enough to fix with a cast.

        bind.invoke( po, 'bind', (Object[])args)

Looking at the source code of BindDynamicMethod, it seems that the first two parameters are just along for the ride.  All the program logic is applied to the third parameter, the Object array.  The object array is pretty much the call you would have done in a controller to the actual bindData() dynamic method.

So far this seems to be working ok for me.  Hopefully, this post gets someone over a little speed bump in the future.

Share/Save/Bookmark

8 Responses to “Using bindData Method in a Grails Service”

  1. CT says:
    March 6th, 2010 at 6:14 pm

    I’m working on something similar with google’s gdata api as a backend. Do you have any good examples of how to set this up?

  2. jt says:
    March 8th, 2010 at 7:55 am

    Not too much beyond what I have here. Ultimately this was the code I had:

    BindDynamicMethod bind = new BindDynamicMethod()

    def args = [ po, params, [exclude:['supplierAddress', 'shipToAddress', 'billToAddress', 'purchaseOrderDetail',
    'orderDate', 'expectedDate']] ]

    bind.invoke( po, ‘bind’, (Object[])args)

  3. groovy says:
    May 31st, 2010 at 8:48 am

    nice groovy, i think its good article. good luck

  4. aeischeid says:
    June 5th, 2010 at 6:58 pm

    Thanks for posting this. Solution worked perfect for me with Grails 1.3.1

    Small thing that made my code more DRY i put the bind object outside of the methods since I was using in a few of them:

    boolean transactional = true
    BindDynamicMethod bind = new BindDynamicMethod()

    def method1(arg1) = {

    bind.invoke(…)
    }

  5. geemang says:
    June 21st, 2010 at 11:54 am

    This is cool! I’m using this technique in my app to marshal data input my domain objects.

    Q? – are you aware of something that does the opposite? E.g. un-marshal my graph of domain objects into a nice hashmap with ognl bean property name and values etc? The properties attr doesn’t do nested objects….

    TIA

  6. jt says:
    June 21st, 2010 at 1:08 pm

    Not sure if I completely follow your question – but you might want to check out Groovy Builders – http://groovy.codehaus.org/Builders

  7. Peter McNeil says:
    August 26th, 2010 at 9:27 pm

    G’day JT,

    I’ve written a short example of binding bindData() to the service so you can just call it as you do in a Controller. See http://nerderg.com/Grails

    Cheers,
    Peter.

  8. jt says:
    August 27th, 2010 at 7:02 am

    Very cool – thanks!!

Leave a Reply