Quantcast

Overriding setter methods in models

classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Overriding setter methods in models

JBodner
Hi,

I'm experimenting with Grails and I'm getting an error that I don't understand.

I'm trying to create a model class with the following fields:

class Foo {
  String name
  String lowerName

  public void setName(name) {
    lowerName = name?.toLowerCase()
    this.name = name
  }
}

I generate scaffolded controller and view for this class.

When I try to create a new instance of Foo, I get this error:

Property [name] of class [class Foo] cannot be null

What am I doing wrong?  How do I create this sort of functionality?

Thanks,

-jon
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Michael Kimsal
Wouldn't this:

  public void setName(name) {
   lowerName = name?.toLowerCase()
   this.name = name
 }

be this:

  public void setName(name) {
   lowerName = name?.toLowerCase()
   this.name = lowerName
 }

???


On Jan 22, 2008 10:52 PM, JBodner <[hidden email]> wrote:

Hi,

I'm experimenting with Grails and I'm getting an error that I don't
understand.

I'm trying to create a model class with the following fields:

class Foo {
 String name
 String lowerName

 public void setName(name) {
   lowerName = name?.toLowerCase()
   this.name = name
 }
}

I generate scaffolded controller and view for this class.

When I try to create a new instance of Foo, I get this error:

Property [name] of class [class Foo] cannot be null

What am I doing wrong?  How do I create this sort of functionality?

Thanks,

-jon

--
View this message in context: http://www.nabble.com/Overriding-setter-methods-in-models-tp15034359p15034359.html
Sent from the grails - user mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email




--
Michael Kimsal
http://webdevradio.com
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
No, the behavior that I want is a case-insensitive field (lowerName) to use as a unique key and a case-sensitive field (name) that displays the case that was originally entered.  Think of a user account system, where you don't want to have two users, one named "BOB" and another named "Bob", but you want to display back the same case that the user originally entered.  

I played around with this a bit more, and from the shell, it was working as I'd expect.  But when I try it from the scaffolding, it fails.

Michael Kimsal wrote
Wouldn't this:

  public void setName(name) {
   lowerName = name?.toLowerCase()
   this.name = name
 }

be this:

  public void setName(name) {
   lowerName = name?.toLowerCase()
   this.name = lowerName
 }

???
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Bugzilla from corey_s@qwest.net
On Tuesday 22 January 2008 10:05:28 pm JBodner wrote:
> No, the behavior that I want is a case-insensitive field (lowerName) to use
> as a unique key and a case-sensitive field (name) that displays the case
> that was originally entered.  Think of a user account system, where you
> don't want to have two users, one named "BOB" and another named "Bob", but
> you want to display back the same case that the user originally entered.
>
> I played around with this a bit more, and from the shell, it was working as
> I'd expect.  But when I try it from the scaffolding, it fails.
>

Try this:

void setName(name) {
   if (name == null) return
   lowerName = name?.toLowerCase()
   this.name = name
}

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
Nope, that didn't do it.

I did a bit of digging, and it seems there's a problem with the generated constructors and overriding setter methods on domain objects.  The save() method uses:

def foo = new Foo(params)

So I tried this out in the grails shell ("go" lines removed for brevity):

groovy> params = [name:'Foo', lowerName:'']
===> {name=Foo, lowerName=}
groovy> x = new Foo(params)
===> Foo : null
groovy> x.name
===> null
groovy> x.lowerName
===> null
groovy> y = new Foo()
===> Foo : null
groovy> y.name = 'Foo'
===> Foo
groovy> y.name
===> Foo
groovy> y.lowerName
===> foo
groovy> z = new Foo(name:'Bar')
===> Foo : null
groovy> z.name
===> null
groovy> z.lowerName
===> null

So, is there an automatic way to get Grails to do the right thing here, or do I need to override the constructors, too?  Is this considered a bug or a feature?

Corey-24 wrote
Try this:

void setName(name) {
   if (name == null) return
   lowerName = name?.toLowerCase()
   this.name = name
}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Bugzilla from corey_s@qwest.net
On Tuesday 22 January 2008 10:30:38 pm JBodner wrote:
> Nope, that didn't do it.
>

Sorry - I meant to put a println in there also - so that when you submitted
via the scaffolding, you could watch your log and see what was going on if
you hadn't already done so.

void setName(name) {
   println "name: ${name}"
   if (name == null) return
   lowerName = name?.toLowerCase()
   this.name = name
}

Have you tried with an actual controller (vs. the scaffolded controller)?



> I did a bit of digging, and it seems there's a problem with the generated
> constructors and overriding setter methods on domain objects.  The save()
> method uses:
>
> def foo = new Foo(params)
>
> So I tried this out in the grails shell ("go" lines removed for brevity):
>
> groovy> params = [name:'Foo', lowerName:'']
> ===> {name=Foo, lowerName=}
> groovy> x = new Foo(params)
> ===> Foo : null
> groovy> x.name
> ===> null
> groovy> x.lowerName
> ===> null
> groovy> y = new Foo()
> ===> Foo : null
> groovy> y.name = 'Foo'
> ===> Foo
> groovy> y.name
> ===> Foo
> groovy> y.lowerName
> ===> foo
> groovy> z = new Foo(name:'Bar')
> ===> Foo : null
> groovy> z.name
> ===> null
> groovy> z.lowerName
> ===> null
>
> So, is there an automatic way to get Grails to do the right thing here, or
> do I need to override the constructors, too?  Is this considered a bug or a
> feature?
>
> Corey-24 wrote:
> > Try this:
> >
> > void setName(name) {
> >    if (name == null) return
> >    lowerName = name?.toLowerCase()
> >    this.name = name
> > }



---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Bugzilla from corey_s@qwest.net
In reply to this post by JBodner
On Tuesday 22 January 2008 10:30:38 pm JBodner wrote:
> Nope, that didn't do it.
>

I set up a test app, and was able to reproduce what you were seeing.

Here's the fix:

void setName( String name ) {
   lowerName = name?.toLowerCase()
   this.name = name
}


Cheers!


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
Thanks; that did it.  Any idea why the type is needed?  For a standard Groovy bean, it isn't.  Is this documented somewhere?  I haven't bought the Grails book yet; I'm waiting for the 2nd edition.

Corey-24 wrote
On Tuesday 22 January 2008 10:30:38 pm JBodner wrote:
> Nope, that didn't do it.
>

I set up a test app, and was able to reproduce what you were seeing.

Here's the fix:

void setName( String name ) {
   lowerName = name?.toLowerCase()
   this.name = name
}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Jason Morris-5
Looks to me like the original problem was down to constraints? By default your bean properties cannot be null.

Either add this to the domain

static constraints =
{
  name(nullable:true)
}

or specify a name when you create the object

Foo myFoo = new Foo(name:"MyName")

Jason

On Jan 23, 2008 1:24 PM, JBodner <[hidden email]> wrote:

Thanks; that did it.  Any idea why the type is needed?  For a standard Groovy
bean, it isn't.  Is this documented somewhere?  I haven't bought the Grails
book yet; I'm waiting for the 2nd edition.


Corey-24 wrote:

>
> On Tuesday 22 January 2008 10:30:38 pm JBodner wrote:
>> Nope, that didn't do it.
>>
>
> I set up a test app, and was able to reproduce what you were seeing.
>
> Here's the fix:
>
> void setName( String name ) {
>    lowerName = name?.toLowerCase()
>    this.name = name
> }
>
>

--
View this message in context: http://www.nabble.com/Overriding-setter-methods-in-models-tp15034359p15041570.html
Sent from the grails - user mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
Nope, it isn't a constraints problem.  It's a method dispatch bug, IMHO.  I did try, from the shell, exactly the constructor you mention:

groovy> z = new Foo(name:'Bar')
===> Foo : null
groovy> z.name
===> null
groovy> z.lowerName
===> null

When the type is specified for the setter, the GORM domain object dispatches correctly.  When the type is not specified, it doesn't.  For standard Groovy Beans, this will work whether or not the type is specified on the setter.
 
Jason Morris-5 wrote
Looks to me like the original problem was down to constraints? By default
your bean properties cannot be null.

Either add this to the domain

static constraints =
{
  name(nullable:true)
}

or specify a name when you create the object

Foo myFoo = new Foo(name:"MyName")
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Service tests and transactions: a question and maybe a solution

DDenoncourt

I have a service that updates the database.
Of course, I have a test for that service.

But, when I run the service test with:

$ grails test-app MyServiceTest

Grails rollbacks my transaction -- even if I use flush.

Why?

Anyway, here's what I did.  

import org.hibernate.SessionFactory
import org.hibernate.Transaction

class MyGrailsAppServiceTests extends GroovyTestCase {

        MyGrailsAppService myGrailsAppService
        SessionFactory sessionFactory
        Transaction tx

        void setUp() {
                tx = sessionFactory.openSession().beginTransaction()
        }
        void tearDown() {
                tx.commit()
        }
        void testSomething() {
                myGrailsAppService.doSomethingThatUpdatesDomainObjects()        
        }

}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Service tests and transactions: a question and maybe a solution

Jean-Noël Rivasseau-5
In tests, Grails always rollback if I am correct, but there is now a way to disable this - search the JIRA for something about "grails 7* slower", I remember reading that bug and this is what prompted GR to provide a way to run tests without rollbacks.

Jean-Noël

On 1/23/08, [hidden email] <[hidden email]> wrote:

I have a service that updates the database.
Of course, I have a test for that service.

But, when I run the service test with:

$ grails test-app MyServiceTest

Grails rollbacks my transaction -- even if I use flush.

Why?

Anyway, here's what I did.  

import org.hibernate.SessionFactory
import org.hibernate.Transaction

class MyGrailsAppServiceTests extends GroovyTestCase {

        MyGrailsAppService myGrailsAppService
        SessionFactory sessionFactory
        Transaction tx

        void setUp() {
                tx = sessionFactory.openSession().beginTransaction()
        }
        void tearDown() {
                tx.commit()
        }
        void testSomething() {
                myGrailsAppService.doSomethingThatUpdatesDomainObjects()        
        }

}

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Bugzilla from corey_s@qwest.net
In reply to this post by JBodner
On Wednesday 23 January 2008 06:24:09 am JBodner wrote:
> Any idea why the type is needed? For a standard Groovy bean, it isn't.
>

Actually I don't know for certain why.

Without specifying type, groovy of course defaults to Object:

void setName(name) ==  void setName (Object name)

I theorize that explicit/specific type is needed for whatever meta binding
grails provides which is necessary for the hibernate interface.


> Is this documented somewhere?  I haven't bought the Grails book yet;
>

I don't know it it's documented somewhere else, but it's not explained
in the Grails book, or the User Guide.




---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

ld@ldaley.com
In reply to this post by JBodner

On 23/01/2008, at 11:24 PM, JBodner wrote:

> Any idea why the type is needed?

Because groovy automatically generates getters/setters for you.  
Consider this ...

class T {

        String s

}

Is really

class T {

        private String s

        public void setS(String s) {
                this.s = s
        }

        public String getS() {
                return this.s
        }
}

So if you add an untyped setter, you end up with

class T {

        private String s

        public void setS(String s) {
                this.s = s
        }

        public void setS(Object s) {
                /* whatever */
        }

        public String getS() {
                return this.s
        }
}

So at despatch time,the closest match will be selected which  if the  
value is a string will be the setter that takes a string. This is not  
a bug, just something to be wary of.

LD.


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
Thanks for the response, but I don't think your explanation is right.

Try this groovy code in the shell:

class T{
  String s

  void setS(s) {
    println "in here"
    this. s= s*2
  }
}

t = new T()
t.s = "Foo"
t.s

If you were correct, then you would not see the print statement in the custom setS, and the value for t.s would be Foo.  Instead, you will see the print statement, and the value will be FooFoo.  At least, I did on my computer with Java 6 and Groovy 1.5.1.  That's because groovy does not generate a getter or setter if you provide one, types specified or not.  

Furthermore, if you were correct about the behavior in the GORM-backed Grails domain objects, then we would see the automatically generated methods invoked when the type isn't specified on the parameter.  We're not; instead, we're seeing nothing invoked.

The Grails/GORM behavior (type needs to be specified in overridden setters or no setter is invoked at all) feels like a bug to me, or at least a pothole.  Time to start looking through the GORM source code...

Luke Daley wrote
On 23/01/2008, at 11:24 PM, JBodner wrote:

> Any idea why the type is needed?

Because groovy automatically generates getters/setters for you.  
Consider this ...

class T {

        String s

}

Is really

class T {

        private String s

        public void setS(String s) {
                this.s = s
        }

        public String getS() {
                return this.s
        }
}

So if you add an untyped setter, you end up with

class T {

        private String s

        public void setS(String s) {
                this.s = s
        }

        public void setS(Object s) {
                /* whatever */
        }

        public String getS() {
                return this.s
        }
}

So at despatch time,the closest match will be selected which  if the  
value is a string will be the setter that takes a string. This is not  
a bug, just something to be wary of.

LD.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

ld@ldaley.com

On 24/01/2008, at 8:52 AM, JBodner wrote:

> If you were correct, then you would not see the print statement in the
> custom setS, and the value for t.s would be Foo.  Instead, you will  
> see the
> print statement, and the value will be FooFoo.  At least, I did on my
> computer with Java 6 and Groovy 1.5.1.  That's because groovy does not
> generate a getter or setter if you provide one, types specified or  
> not.

Good points, statement retracted :)

LD.

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Christian Laakmann
My suspicion is, that this has nothing to do with GORM in itself but with Hibernate.

Coming from a strict Java-background, Hibernate will certainly search for a setter method with type-information like

void setString(String s)

Cheers
Christian


Luke Daley wrote
On 24/01/2008, at 8:52 AM, JBodner wrote:

> If you were correct, then you would not see the print statement in the
> custom setS, and the value for t.s would be Foo.  Instead, you will  
> see the
> print statement, and the value will be FooFoo.  At least, I did on my
> computer with Java 6 and Groovy 1.5.1.  That's because groovy does not
> generate a getter or setter if you provide one, types specified or  
> not.

Good points, statement retracted :)

LD.

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

Bugzilla from corey_s@qwest.net
On Wednesday 23 January 2008 04:05:12 pm Christian Laakmann wrote:
> My suspiscion is, that this has nothing to do with GORM in itself but with
> Hibernate.
>

+1


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Overriding setter methods in models

JBodner
In reply to this post by Christian Laakmann
Yeah, I was wondering about that, too, but I don't think Hibernate is involved when doing a

x = new Foo(name:"Test")

That will fail to assign a value to name if you override setName in Foo, and don't specify a type on the parameter.  And again, note that this will work correctly with a standard Groovy bean.

I haven't checked the GORM source code yet to see what's going on, so I'm hesitant to guess, but it looks like there's a difference in behavior in the constructors of GORM beans and POGOs.

Christian Laakmann wrote
My suspicion is, that this has nothing to do with GORM in itself but with Hibernate.

Coming from a strict Java-background, Hibernate will certainly search for a setter method with type-information like

void setString(String s)

Cheers
Christian
Loading...