Validation and Data Binding
Add Extra Valid Domains and Authorities for URL Validation
Grails has a built-in URL constraint to check if a String value is a valid URL. We can use the constraint in our code to check for example that the user input http://www.mrhaki.com is valid and http://www.invalid.url is not. The basic URL validation checks the value according to standards RFC1034 and RFC1123. If want to allow other domain names, for example server names found in our internal network, we can add an extra parameter to the URL constraint. We can pass a regular expressions or a list of regular expressions for patterns that we want to allow to pass the validation. This way we can add IP addresses, domain names and even port values that are all considered valid. The regular expression is matched against the so called authority part of the URL. The authority part is a hostname, colon (:) and port number.
In the following sample code we define a simple command object with a String property address. In the constraints block we use the URL constraint. We assign a list of regular expression String values to the URL constraint. Each of the given expressions are valid authorities, we want the validation to be valid. Instead of a list of values we can also assign one value if needed. If we don’t want to add extra valid authorities we can simple use the parameter true.
// Sample command object with URL constraint.
class WebAddress {
String address
static constraints = {
address url: ['129.167.0.1:\\d{4}', 'mrhaki']
// Or one String value if only regular expression is necessary:
// address url: '129.167.0.1:\\d{4}'
// Or simple enable URL validation and don't allow
// extra hostnames or authorities to be valid
// address url: true
}
}
Code written with Grails 2.2.4
Original blog post written on October 13, 2013.
Combining Constraints with Shared Constraints
In our Grails applications we might have fields that need the same combination of constraints. For example we want all email fields in our application to have a maximum size of 256 characters and must apply to the email constraint. If we have different classes with an email field, like domain classes and command objects, we might end of duplicating the constraints for this field. But in Grails we can combine multiple constraints for a field into a single constraint with a new name. We do this in grails-app/conf/Config.groovy where we add the configuration property grails.gorm.default.constraints. Here we can define global constraints with can be used in our Grails application.
Let’s add a custom email constraint in our application:
// File: grails-app/conf/Config.groovy
...
grails.gorm.default.constraints = {
// New constraint 'customEmail'.
customEmail(maxSize: 256, email: true)
}
...
To use the constraint in a domain class, command object or other validateable class we can use the shared argument for a field in the constraints configuration. Suppose we want to use our customEmail constraint in our User class:
// File: src/groovy/com/mrhaki/grails/User.groovy
package com.mrhaki.grails.User
@grails.validation.Validateable
class User {
String username
String email
static constraints = {
// Reference constraint from grails.gorm.default.constraints
// with shared argument.
email shared: 'customEmail'
}
}
Code written with Grails 2.3.7.
Original blog post written on March 17, 2014.
Custom Data Binding with @DataBinding Annotation
Grails has a data binding mechanism that will convert request parameters to properties of an object of different types. We can customize the default data binding in different ways. One of them is using the @DataBinding annotation. We use a closure as argument for the annotation in which we must return the converted value. We get two arguments, the first is the object the data binding is applied to and the second is the source with all original values of type SimpleMapDataBindingSource. The source could for example be a map like structure or the parameters of a request object.
In the next example code we have a Product class with a ProductId class. We write a custom data binding to convert the String value with the pattern {code}-{identifier} to a ProductId object:
package mrhaki.grails.binding
import grails.databinding.BindUsing
class Product {
// Use custom data binding with @BindUsing annotation.
@BindUsing({ product, source ->
// Source parameter contains the original values.
final String productId = source['productId']
// ID format is like {code}-{identifier},
// eg. TOYS-067e6162.
final productIdParts = productId.split('-')
// Closure must return the actual for
// the property.
new ProductId(
code: productIdParts[0],
identifier: productIdParts[1])
})
ProductId productId
String name
}
// Class for product identifier.
class ProductId {
String code
String identifier
}
The following specification shows the data binding in action:
package mrhaki.grails.binding
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
import grails.databinding.SimpleMapDataBindingSource
@TestMixin(GrailsUnitTestMixin)
class ProductSpec extends Specification {
def dataBinder
def setup() {
// Use Grails data binding
dataBinder = applicationContext.getBean('grailsWebDataBinder')
}
void "productId parameter should be converted to a valid ProductId object"() {
given:
final Product product = new Product()
and:
final SimpleMapDataBindingSource source =
[productId: 'OFFCSPC-103910ab24', name: 'Swingline Stapler']
when:
dataBinder.bind(product, source)
then:
with(product) {
name == 'Swingline Stapler'
with(productId) {
identifier == '103910ab24'
code == 'OFFCSPC'
}
}
}
}
If we would have a controller with the request parameters productId=OFFCSPC-103910ab24&name=Swingline%20Stapler the data binding of Grails can create a Product instance and set the properties with the correct values.
Written with Grails 2.5.0 and 3.0.1.
Original blog post written on April 27, 2015.