Grails 3 @Delegate notation, using a domain object
Asked Answered
C

3

8

Under Grails 2.4.4, we had classes we used as wrappers for domain objects.

They would look like this:

class Foo {
  @Delegate
  OurDomainClass ourDomainClass
  ...

}

This worked, but when trying to compile under Grails 3.0.11, we get this:

> Foo.groovy: 14: Can't have an abstract method in a non-abstract class.
> The class 'Foo' must be declared abstract or the method
> 'org.springframework.validation.Errors
> org_grails_datastore_gorm_GormValidateable__errors$get()' must be
> implemented.  @ line 14, column 1.    class Foo {    ^

Removing the @Delegate annotation will make compilation pass, but calls to methods of the underlying class obviously then do not work.

Is there a way to work around this or to achieve this same behavior and have it pass compilation under Grails 3?

Christyna answered 6/1, 2016 at 16:53 Comment(4)
have you tried adding @Validatable to your wrappers?Repute
In grails 3.x commands implements interface Validatable instead @Validatable...Zak
Excuse my ignorance but what is the idea behind wrapping the Domains with a class? Is it to decouple the DAO layer from the view layer so that this way the views have zero knowledge about the database structure? If so, does your service layer always return Wrapper objects? What about for your inserts and updates? Does your Service layer take in always Wrapper objects?Christianize
@Christianize - This is so that the domain class itself is not cluttered with a bunch of methods - it's essentially being used as a Decorator.Christyna
R
1

Does good old static hasMany = [] or static hasOne = [] won't do the job? Of course wrappers would be domain classes then too.

Resolute answered 30/6, 2016 at 8:58 Comment(0)
T
0

You can work around this by changing the wrapper class to implement the GORM traits:

class Foo implements GormValidateable, DirtyCheckable, Validateable {
    @Delegate
    OurDomainClass ourDomainClass
    ...
}

I went further and created my own interface:

class Foo implements GormDelegateHack {
    @Delegate
    OurDomainClass ourDomainClass
    ...
}

interface GormDelegateHack extends GormValidateable, DirtyCheckable, Validateable {
}

I filed issue #856 against grails-data-mapping, although it may be a Groovy bug.

Trypsin answered 24/1, 2017 at 0:36 Comment(0)
M
0

@timbonicus' solution works for Grails 3, but on Grails 4 it fails with multiple errors.

Ended up changing the @Delegate classes to Groovy traits as an alternative. It will still be separated, as traits support multiple inheritance and implemented methods. Also, it won't be necessary to add another call to an object as embedded, hasMany and hasOne would require.

trait OurDomainClass {}

trait OurOtherDomainClass {}

class Foo implements OurDomainClass, OurOtherDomainClass {}

If you are creating a plugin, you can add methods at compile time with traits.

Melanie answered 11/8, 2021 at 1:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.