Search code examples
grailsmany-to-manyduck-typing

Grails: duck typing and many-to-many collection classes


In my Grails app, a Person has a Fondness for Something - and that Something could be an Idea, a Decision, a Group, or another Person.

In Java I would impose a Something interface so that each of these classes could be passed in as a Something type.

In Groovy/Grails, I had it working where Something is a Groovy class and the Fondness class is a collection class that mapped Persons to Somethings.

I stumble when I try to leverage Duck Typing in this instance. How do I set up a collection class mapping Person to any of my group of classes, without imposing an interface?

Thanks for any advice! I am excited to hear how G/G developers would approach this.

-Bill


Solution

  • I ran across this Nabble thread which may be similar to what you're after. It's an interesting solution, and seems kind of hacky, but would probably work alright.

    Here's a code sample from the thread (courtesy of Martin Dow - if he runs across this and posts this as an answer, I'll remove it from my answer and give him the upvote).

    class SomeDomainClass { 
      Long associationId
      String associationClass
      def getAssociation() {
        // Handle proxied class names
        def i = associationClass.indexOf('_$$_javassist')
        if (i > -1) associationClass = associationClass[0..i-1]
        getClass().classLoader.loadClass(associationClass).get(associationId)
      }
      def setAssociation(association) {
        associationId = association.id
        associationClass = association.class.name
      }
    }
    

    Here are a couple options that do involve types that might give you some direction.

    Enums

    class Person {
        static hasMany = [fondnessess: Something]
    }
    
    enum Something {
        ONE_SOMETHING,
        ANOTHER_SOMETHING;
    }
    

    Inheritance

    (I'm not the hugest fan of inheritance, but sometimes it's an okay solution.)

    class Person {
        static hasMany = [somethings: Something]
    }
    
    class Something {
        // could be abstract, but look out for
        // http://jira.grails.org/browse/GRAILS-6780
    }
    
    class OneSomething extends Something { ... }
    
    class AnotherSomething extends Something { ... }
    

    It kind of depends on how much logic each Something implementation needs to define. Both of these examples can be made to work, and there are probably other solutions out there, too.