dmux
dmux

Reputation: 442

Grails domain object storing Map<K,V>

I know from the Grails/GORM documentation that if you wish to store a Map of objects, both the key and value need to be Strings: Map<String,String>.

I'd like to use another domain object (Animal) as the key within this map, but due to the constraint above, that's not possible. The identifier of Animal can be easily converted to a string type, but if I were to do that, I don't believe GORM would be smart enough to perform the mapping when retrieving the parent object.

Has anyone run into this?

Upvotes: 0

Views: 1591

Answers (1)

V H
V H

Reputation: 8587

I think this should work:

Assuming you have a domainclass that has a map:

class Test {
   String name
   Map myAnimals=[:]

  //When given a specific key it will return actual animal object
  def findAnimal(String myKey) {
    return myAnimals.find{it.key==myKey}?.value
    //What above is doing can be seen broken down here:
    //def ani = myAnimals.find{it.key==myKey}
    //println "ANI::: ${ani} ${ani.value}"
    //def animal = ani?.value
    //return animal

  }
}

In a service when saving to map

class TestService {
    def save(values) {
    Test test1 = new Test()
    test1.name='something'
    // so to add 3 of animal objects above values would be
    def animal1=Animal.find()
    String key1='ANI'  //For animals 
    def animal2=Monkey.find()  // where Monkey extends Animal (hence the keys)
    String key2='MON'  //For monkeys only
    test1.myAnimals[key1]=animal1
    test1.myAnimals[key2]=animal2
    test1.save()

      /**
      * When you have a real values map that contains useful method you can
      * do it this way - left commented out FYI on manual process above
      Test test = new Test()
      // you now have some map of values coming in that contains a key 
      // and actual object so you could make this up if you are testing
     values.animals?.each{k,v->
                test.myAnimals[k]=v
            }
    }    
    test.save()
    */        
 }

So the first example the values.each is where you have built your own map that contains a key and actual domain object being saved.

The second test1 example is where I did it manually without having automated values to pass in as a test and possibly best starting point.

Then when you have test object to get actual animal (as you can see limited to ) key so one animal one monkey one bird etc

When you have

Test test = Test.findByName('something)
def animal = test.findAnimal('ANI')
def monkey = test.findAnimal('MON')
println "animal is ${animal} ${animal.getClass()} monkey is ${monkey} ${monkey.getClass()}"

This now will look up the domain class method and attempt to return animal object as per call

Before launching this I will need 1 animal and 1 Monkey added since it gets or does a find or first object above. So in my bootstrap:

import test.Animal
import test.Monkey

class BootStrap {

    def init = { servletContext ->

        Animal animal = new Animal()
        animal.name='Daffy Duck'
        animal.save(flush:true)
        Monkey monkey = new Monkey()
        monkey.name='King Kong'
        monkey.save(flush:true)
    }
    def destroy = {
    }
}

When I run it I get from that println:

animal is class test.Animal class java.lang.Class monkey is class test.Monkey class java.lang.Class

Also getting some class to string error unsure which bit is causing it - the println from the output looks as you desire.

You may have to choose a different method to hold the keys and use Animal as the main class to query so some other code for the key then you can change the findByAnimal to always return Animal object:

//When given a specific key it will return actual animal object
    Animal findAnimal(String myKey) {
      Animal animal = myAnimals.find{it.key==myKey}?.value
      return animal
    }

Higher call got changed due to it being Animal or Monkey which extended Animal. Two missing classes from above example:

package test

class Animal {
    String name

}
package test

class Monkey extends Animal {


}

Upvotes: 1

Related Questions