Search code examples
grailsdata-bindinggrails-2.0grails-controllercommand-objects

Grails command object not binding to 'def' type


Having issues trying to bind a param to a command object field defined as 'def'.

I have the following command object:

package command

import grails.validation.Validateable

@Validateable
class TestBindCommand {

    String fieldType
    def fieldValue
}

I have the following controller to test whether the params have binded correctly:

package command.binding

import command.TestBindCommand

class TestBindingController {

    def index() { }

    def testBinding(TestBindCommand testBindCommand) {
        println("fieldType: " + testBindCommand.fieldType)
        println("fieldValue: " + testBindCommand.fieldValue)
        render("fieldType: ${testBindCommand.fieldType} - fieldValue: ${testBindCommand.fieldValue}")
    }
}

Finally, I have the following ajax request to post the params to the testBinding method above:

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>Index</title>
</head>
<g:javascript library="jquery" plugin="jquery"/>
<script>
    $( document ).ready(function() {
        $.post('/command-binding/testBinding/testBinding', { fieldType: "String", fieldValue : "hello world"},
            function(returnedData){
                console.log(returnedData);
            });
    });
</script>
<body>
Index Page
</body>
</html>

If you change the type of fieldValue to String it begins binding. If you then switch it back to def it still works?! If you do a grails clean and restart the app with fieldValue set as def then it won't work again!? I've debugged down into the DataBindingUtils.java and it appears that the field isn't getting added to the whitelist when it is of type 'def'.

Sample project can be found here:

https://github.com/georgy3k/command-binding

Grails version 2.5.6


Solution

  • I've debugged down into the DataBindingUtils.java and it appears that the field isn't getting added to the whitelist when it is of type 'def'.

    That is correct, and by design. By default dynamically typed properties do not participate in mass property data binding.

    From https://grails.github.io/grails2-doc/2.5.6/ref/Constraints/bindable.html:

    Properties which are not bindable by default are those related to transient fields, dynamically typed properties and static properties.

    If you really want to make a dynamically typed property participate in mass property binding, you have to opt into that with something like this:

    class TestBindCommand {
    
        String fieldType
        def fieldValue
    
        static constraints = {
            fieldValue bindable: true
        }
    }
    

    That said, for command objects in particular, there is no good reason to have a dynamically typed property.

    I hope that helps.