7.1.10 Command Objects 2.3.8

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 7.1.10 Command Objects - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 2.3.8 ## 7.1.10 Command Objects Grails controllers support the concept of command objects. A command object is a class that is used in conjunction with data binding, usually to allow validation of data that may not fit into an existing domain class. Note: A class is only considered to be a command object when it is used as a parameter of an action. #### Declaring Command Objects Command object classes are defined just like any other class.

    @grails.validation.Validateable
    class LoginCommand {
        String username
        String password    static constraints = {
            username(blank: false, minSize: 6)
            password(blank: false, minSize: 6)
        }
    }
In this example, the command object is marked with the `Validateable` annotation. The `Validateable` annotation allows the definition of constraints just like in domain classes. If the command object is defined in the same source file as the controller that is using it, Grails will automatically mark it as `Validateable`. It is not required that command object classes be validateable. #### Using Command Objects To use command objects, controller actions may optionally specify any number of command object parameters. The parameter types must be supplied so that Grails knows what objects to create and initialize. Before the controller action is executed Grails will automatically create an instance of the command object class and populate its properties by binding the request parameters. If the command object class is marked with `Validateable` then the command object will be validated. For example:

    class LoginController {    def login(LoginCommand cmd) {
            if (cmd.hasErrors()) {
                redirect(action: 'loginForm')
                return
            }        // work with the command object data
        }
    }
If the command object's type is that of a domain class and there is an `id` request parameter then instead of invoking the domain class constructor to create a new instance a call will be made to the static `get` method on the domain class and the value of the `id` parameter will be passed as an argument. Whatever is returned from that call to `get` is what will be passed into the controller action. This means that if there is an `id` request parameter and no corresponding record is found in the database then the value of the command object will be `null`. #### Command Objects And Request Parameter Names Normally request parameter names will be mapped directly to property names in the command object. Nested parameter names may be used to bind down the object graph in an intuitive way. In the example below a request parameter named `name` will be bound to the `name` property of the `PersonCommand` instance and a request parameter named `address.city` will be bound to the `city` property of the `address` property in the `PersonCommand`.

    class StoreController {
        def buy(PersonCommand buyer) {
            // …
        }
    }class PersonCommand {
        String name
        Address address
    }class Address {
        String city
    }
A problem may arise if a controller action accepts multiple command objects which happen to contain the same property name. Consider the following example.

    class StoreController {
        def buy(PersonCommand buyer, ProductCommand product) {
            // …
        }
    }class PersonCommand {
        String name
        Address address
    }class Address {
        String city
    }class ProductCommand {
        String name
    }
If there is a request parameter named `name` it isn't clear if that should represent the name of the `ProductCommand` or the name of the `PersonCommand`. To help deal with this the framework imposes special rules for mapping parameter names to command object types. If a command object class name ends with "Command" and there are request parameters with a name which begins with the name of the command object class name minus the "Command" suffix then the data binding will treat all parameters that begin with that name as belonging to the corresponding command object. For example, the `product.name` request parameter will be bound to the `name` property in the `ProductCommand` instance, the `person.name` request parameter will be bound to the `name` property in the `PersonCommand` instance and the `person.address.city` request parameter will be bound to the `city` property of the `address` property in the `PersonCommand` instance. A potentially problematic scenario is one where the command object class name ends with "Command" and the class contains a property with a name that matches the command object class name minus the "Command" suffix as shown below.

    class StoreController {
        def buy(PersonCommand buyer) {
            // …
        }
    }class PersonCommand {
        Person person
    }class Person {
        String name
    }
In the example above one might expect a request parameter named `person.name` to be bound to the `name` property of the `person` property in the `PersonCommand` instance but because of the special handling described above that would not work. The problem is since the `person.name` request parameter begins with "person" and that happens to match the beginning of the command object class name, "PersonCommand", everything after the "person." prefix represents what is bound to the command object. Since there is no `name` property in the `PersonCommand` class that request parameter is ignored during data binding. The application could deal with this by renaming the `PersonCommand` class, renaming the `person` property name in the `PersonCommand` class or by fully qualifying the request parameter name to be `person.person.name`. The first "person" there is the qualifier which tells the framework the type of command object to bind this request paramter to. The second "person" there represents the property name in `PersonCommand` that `name` should be bound to. #### Command Objects and Dependency Injection Command objects can participate in dependency injection. This is useful if your command object has some custom validation logic which uses a Grails service:

    @grails.validation.Validateable
    class LoginCommand {    def loginService    String username
        String password    static constraints = {
            username validator: { val, obj ->
                obj.loginService.canLogin(obj.username, obj.password)
            }
        }
    }
In this example the command object interacts with the `loginService` bean which is injected by name from the Spring `ApplicationContext`. #### Binding The Request Body To Command Objects When a request is made to a controller action which accepts a command object and the request contains a body, Grails will attempt to parse the body of the request based on the request content type and use the body to do data binding on the command object. See the following example.

    // grails-app/controllers/bindingdemo/DemoController.groovy
    package bindingdemoclass DemoController {    def createWidget(Widget w) {
            render "Name: ${w?.name}, Size: ${w?.size}"
        }
    }class Widget {
        String name
        Integer size
    }
    $ curl -H "Content-Type: application/json" -d '{"name":"Some Widget","size":"42"}' localhost:8080/myapp/demo/createWidget
     Name: Some Widget, Size: 42
    ~ $
    $ curl -H "Content-Type: application/xml" -d '<widget><name>Some Other Widget</name><size>2112</size></widget>' localhost:8080/bodybind/demo/createWidget
     Name: Some Other Widget, Size: 2112
    ~ $
Note that the body of the request is being parsed to make that work. Any attempt to read the body of the request after that will fail since the corresponding input stream will be empty. The controller action can either use a command object or it can parse the body of the request on its own (either directly, or by referring to something like request.JSON), but cannot do both.

    // grails-app/controllers/bindingdemo/DemoController.groovy
    package bindingdemoclass DemoController {    def createWidget(Widget w) {
            // this will fail because it requires reading the body,
            // which has already been read.
            def json = request.JSON        // ...    }
    }
| Quick Reference (hide)