Setting groovy getter/setter methods via constructor in grails domain class

constructorgrailsgroovyjavabeans

I have a grails unit test that has code similar to below and is appears that setting fields via getter/setter methods doesn't work with constructors (even though it actually works with non-domain classes).

I understand that the following works with properties:

class Person {
  def firstName
  def lastName

  def getFullName() {
    return "$firstName $lastName"
  }

  def setFullName(name) {
    firstName = name.split(" ")[0]
    lastName = name.split(" ")[1]
  }
}

def = new Person(fisrtName: "Joe", lastName: "Bloggs")

But when I do the following the first and last name fields don't get set:

def = new Person(fullName: "Joe Bloggs")

Is there a way to set fields via methods in a groovy contstructor?

Best Answer

What version of groovy are you using? This works fine for me with groovy 1.8.6 and I think it's worked for that way for a very long time:

class Person {
  def firstName
  def lastName

  def getFullName() {
    return "$firstName $lastName"
  }

  def setFullName(name) {
    firstName = name.split(" ")[0]
    lastName = name.split(" ")[1]
  }
}

def p1 = new Person(firstName: "Joe", lastName: "Bloggs")
def p2 = new Person(fullName: "Joe Bloggs")

assert p1.firstName == p2.firstName
assert p1.lastName == p2.lastName

Updated:

Just tried this on grails 2.0.3. You need to be more explicit in your method signatures for grails to work. I changed the method signature for the getter to be String and the setter to be void and it worked. It did not work with just def. Grails 2 is much more strict about matching signatures than previous versions of grails were and I'm betting that this is part of it.

Also, you should specify that the fullName "property" is transient as it isn't a real property that should get persisted in the database. Here's the domain and test class that work for me in grails 2.0.3:

Person.groovy:

package com.example

class Person {
    String firstName
    String lastName

    static transients = ["fullName"]

    String getFullName() {
        return "$firstName $lastName"
    }

    void setFullName(String name) {
        firstName = name.split(" ")[0]
        lastName = name.split(" ")[1]
    }
}

PersonTests.groovy:

package com.example



import grails.test.mixin.*
import org.junit.*

/**
 * See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
 */
@TestFor(Person)
@Mock([Person])
class PersonTests {

    void testFullName() {
        Person p1 = new Person(firstName: "Joe", lastName: "Bloggs").save(failOnError: true)
        Person p2 = new Person(fullName: "Joe Bloggs").save(failOnError: true)

        assert p1.firstName == p2.firstName
        assert p1.lastName == p2.lastName
        assert p1.fullName == p2.fullName
    }
}
Related Topic