Table of contents
  1. The Grails Parameter Map
  2. Command Object with Validation-*
    1. command object allows you to validate with services
      1. Custom Validator for Nested Command objects in a list
      2. Import and excluding other domain constrains
      3. JSON return bodies Spring/Jackson examples
        1. jackson-json-view-annotation
        2. spring-mvc-ann-jackson




The Grails Parameter Map

Using Param map Object

def paramMap = ["firstName": "brandon", "lastName": "paxton", "email": "bpaxton@talentplus.com", "assessmentType": "AO6"]
def x = new grails.web.servlet.mvc.GrailsParameterMap(paramMap, request)

Command Object with Validation-*

command object allows you to validate with services

GRAILSCommandObject

Custom Validator for Nested Command objects in a list

creating error code

Error Object = package org.springframework.validation (Public Interface Errors)

Example com.talentbank.tbex.SelfServiceIntegration.WSConfigCommand.rest

(Validator)[https://docs.grails.org/latest/ref/Constraints/validator.html]

rest nullable: true, validator: { RESTCommand restCmd, WSConfigCommand obj ->
    return (obj?.wSConfigTypes?.size() > 0) ? null : "error: must have config rest, ftp, or soap"
}

error object params Example - Errors.java

// void reject(String errorCode, Object[] errorArgs, String defaultMessage);

"com.talentbank.tbex.SelfServiceIntegration.WSConfigCommand.rest" , Object {
    "rest" :
    "${WSConfigCommand.class}"
} , "Property[{ 0 }] of class [ { 1 } ] with value [ { 2 } ] does not pass custom validation"
user.errors.reject('user.password.doesnotmatch', ['password', 'class User'] as Object[], '[Property [{0}] of class [{1}] does not match confirmation]')

usage com.talentbank.tbex.SelfServiceIntegration.CommandObjects.IntegrationCommand

private void validateSubCommandObject(Validateable childCmdObj) {
    if (!childCmdObj.validate()) {
        childCmdObj.errors.allErrors.each { ObjectError errObj ->
            String msg = errObj.defaultMessage
            errObj.arguments.eachWithIndex { Object err, int index ->
                msg = msg.replace("{${index}}", "${err}")
            }
            errors.reject(errObj.codes[0], errObj.arguments, msg)
        }
    }
}

void beforeValidate() {
    ["wSConfig", "clientResultConfig"].each { String prop ->
        if (this[prop]) {
            validateSubCommandObject(this[prop] as Validateable)
        } else {
            errors.reject($/com.talentbank.tbex.SelfServiceIntegration.validator.null.${prop}/$,
                    ["$prop", "class IntegrationCommand"] as Object[],
                    $/Property ${prop} of class IntegrationCommand is null/$)
        }
    }

    if (this.clientEntityMap) {
        this.clientEntityMap.each { ClientEntityMapType key, List<ClientEntityDetailsCommand> value ->
            value.each { validateSubCommandObject(it as Validateable) }
        }
    }

}

this forces validate on nested command object, then adds errors to parent errors, only the parent need to be confirmed

List<WSConfigCommand> wSConfig

void validateWSConfig() {
    if (this.wSConfig.size() > 0) {
        this.wSConfig.each { WSConfigCommand cmd ->
            if (!cmd.validate()) {
                cmd.errors.allErrors.each {
                    errors.reject(it.codes[0], it.arguments, it.defaultMessage)
                }
            }
        }
    }
}

Import and excluding other domain constrains

        importFrom SOAPClientOrderConfig, exclude: ["binarySecTokenEncodingType", "binarySecTokenValueType", "countryCodeFormat"]

JSON return bodies Spring/Jackson examples

jackson-json-view-annotation

spring-mvc-ann-jackson