Grails: How to mock a domain field validator? - grails

Is there some way to mock a domain field validator?
Currently, my code in the domain class is looking like this:
isPrimary(validator: { Boolean value, Person obj ->
.......
}
And I need to mock this function.
I tried to use it like:
Person.metaClass.static.isPrimary.validator = { Boolean value, Person obj ->
.......
}
And it didn't work, any suggestions how to solve this issue ?

Here is an example:
class Person {
Boolean isPrimary
static constraints = {
isPrimary validator: isPrimaryValidator
//or this for a fully qualified validator
//isPrimary validator: Person.isPrimaryValidator
}
static isPrimaryValidator = { Boolean value, Person obj ->
//some validation
}
}
//in Test
Person.metaClass.'static'.isPrimaryValidator = { Boolean value, Person obj ->
//Do something else
}

Related

How to map Grails domain class properties to non-matching json string?

Is there a built-in / easy way to set mappings between domain class properties and JSON strings that don't have exact matches for the property names?
For example, when I have a domain class:
class Person {
String jobTitle
String favoriteColor
static constraints = {
jobTitle(blank: false)
favoriteColor(blank: false)
}
}
And someone's giving me the following JSON:
{ "currentJob" : "secret agent", "the-color" : "red" }
I'd like to be able to still do this:
new Person(request.JSON).save()
Is there a way in groovy/grails for me to map currentJob -> jobTitle and the-color -> favorite color?
EDIT:
I've done a little experimenting, but I still haven't gotten it working. But I have found out a couple interesting things...
At first I tried overwriting the setProperty method:
#Override
setProperty(String name, Object value) {
if(this.hasProperty(name)) this[name] = value
else {
switch(name) {
'currentJob': this.jobTitle = value; break;
'the-color': this.favoriteColor = value; break;
}
}
}
But this doesn't work for two reasons: 1) setProperty is only called if there is a property that matches name and 2) "this[name] = value" calls setProperty, leading to an infinite recursive loop.
So then I thought, well screw it, I know what the incoming json string looks like (If only I could control it), I'll just get rid of the line that handles the scenario where the names match and I'll override hasProperty, maybe that will work:
#Override
void setProperty(String name, Object value) {
switch(name) {
'currentJob': this.jobTitle = value; break;
'the-color': this.favoriteColor = value; break;
}
}
#Override
boolean hasProperty(String name) {
if(name == "currentJob" || name == "the-color") return true
return false
}
But no, that didn't work either. By a random stroke of luck I discovered, that not only did I have to overwrite hasProperty(), but I also had to have an empty setter for the property.
void setCurrentJob(){ }
That hack worked for currentJob - I guess setProperty only gets called if hasProperty returns true and there is a setter for the property (Even if that setter is auto generated under the covers in grails). Unfortunately I can't make a function "setThe-Color" because of the dash, so this solution doesn't work for me.
Still stuck on this, any help would definitely be appreciated.
EDIT:
Overriding the void propertyMissing(String name, Object value){} method is called by this:
Person person = new Person()
person["currentJob"] = "programmer"
person["the-color"] = "red"
But not by this:
Person person = new Person(["currentJob":"programmer", "the-color":"red"])

Using Custom Validator on List

I have a Command Object as follows :
class TestCreationCommand {
String title
List testItems = [].withLazyDefault {new VocabQuestion()}
static constraints = {
title(blank:false,maxLength:150)
testItems( validator: { ti ->
ti.each {it.validate()}
} )
}
}
Test Items is a list of VocabQuestion objects. VocabQuestion is as follows :
class VocabQuestion {
static constraints = {
question(blank:false,maxLength:150)
answer(blank:false,maxLength:40)
}
static belongsTo = [vocabularyTest: VocabularyTest]
String question
String answer
}
I'm attempting to validate the constraints on the VocabQuestion using a custom vaildator ( in the constraints of the Command class above ), but I keep getting the following error message.
Return value from validation closure [validator] of property [testItems] of class [class vocabularytest.TestCreationCommand] is returning a list but the first element must be a string containing the error message code
I have had many different attempts at this .....
I am not sure what the message is telling me or how to go about debugging what the return value from the closure is.
Can anyone provide me any pointers?
You are not returning what Grails understands. You can't expect to just return anything and have Grails know what to do with it. Return a boolean or an error string.
static constraints = {
title(blank:false,maxLength:150)
testItems( validator: { ti ->
Boolean errorExists = false
ti.each {
if (!it.validate()) {
errorExists = true
}
}
errorExists
})
}
Check out this SO question It might be the format of the validator you need.
The .every will return a boolean.

Grails custom validater, getting a reference to the field name

I am trying to write a generic custom validator for a property, to make it generic i need a reference to the field name within the closure, the code is as follows
In config.groovy
grails.gorm.default.constraints = {
nameShared(validator: {val, obj, errors->
Pattern p = Pattern.compile("[a-zA-Z0-9-]{1,15}")
Matcher m = p.matcher(val)
boolean b = m.matches()
if(!b)
errors.rejectValue('name', "${obj.class}.name.invalid", "Name is invalid")
})
in My domain class
class Student{
String name
static constraints = {
name(shared:'nameShared')
}
}
class Teacher{
String firstName
String lastName
static constraints = {
firstName(shared:'nameShared')
}
}
I want to use the same validator for both name and firstName, but since i am hardcoding the fieldName in the validator, it will always work for name and not firstName, so i want to know if there is anyway i can get a reference to the fieldname and make the validator generic, please help
You could use the variable propertyName to get the name of the validated property.
From the grails docs:
The Closure also has access to the name of the field that the constraint applies to using propertyName
myField validator: { val, obj -> return propertyName == "myField" }
You could wrap your validator-closure inside another function like this:
def getValidator(myValue) {
return { val, obj, errors ->
// make use of myValue
}
}
myField validator: getValidator('foo')

External function definition to validate in Domain Class

My validation looks like:
static constraints =
{
someProperty validator: { val, obj ->
// a lot of code here
}
}
How can I define external function which will pass to this validation (val, obj requierd) ?
Now my code isn't clear in constraints closures... there's too much validation code for someProperty.
How can I change it?
By creating a groovy class in the src/groovy directory, like :
public class CustomValidators {
static validateMe = { val, obj ->
// a dummy example...
return val < 1
}
}
Then, on your domain class use it like below :
static constraints =
{
someProperty validator: CustomValidators.validateMe
}

How to refer to another property in a custom Grails validator?

I have a property that can be nullable or required depending on the status of another variable.
class Person{
name()
civilStatus(inList:['Single','Married','Divorced','Widowed'])
partnerOrSpouse()
}
the partnerOrSpouse property is nullable or not depending on the value of the civilStatus property.
You can use a custom validator. Using the two-parameter version, the first is the value being validated and the second is the domain class instance. You can refer to other properties via the 'obj' parameter:
class Person {
...
static constraints = {
name()
civilStatus inList:['Single','Married','Divorced','Widowed']
partnerOrSpouse validator: { val, obj ->
if (obj.civilStatus == 'Single') {
return 'some.error.code'
}
}
}
}

Resources